blob: 96d07a859b296b5223d7355f56d1fbb591535b17 [file] [log] [blame]
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001// Copyright 2010 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include <stdlib.h>
29
30#include "v8.h"
31
32#include "accessors.h"
33#include "api.h"
34#include "arguments.h"
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000035#include "codegen.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000036#include "compilation-cache.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000037#include "compiler.h"
38#include "cpu.h"
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000039#include "dateparser-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000040#include "debug.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000041#include "deoptimizer.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000042#include "execution.h"
43#include "jsregexp.h"
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000044#include "liveedit.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000045#include "parser.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000046#include "platform.h"
47#include "runtime.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000048#include "runtime-profiler.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000049#include "scopeinfo.h"
ager@chromium.org7c537e22008-10-16 08:43:32 +000050#include "smart-pointer.h"
ager@chromium.org18ad94b2009-09-02 08:22:29 +000051#include "stub-cache.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000052#include "v8threads.h"
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000053#include "string-search.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000054
kasperl@chromium.org71affb52009-05-26 05:44:31 +000055namespace v8 {
56namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000057
58
ager@chromium.org3e875802009-06-29 08:26:34 +000059#define RUNTIME_ASSERT(value) \
60 if (!(value)) return Top::ThrowIllegalOperation();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000061
62// Cast the given object to a value of the specified type and store
63// it in a variable with the given name. If the object is not of the
64// expected type call IllegalOperation and return.
65#define CONVERT_CHECKED(Type, name, obj) \
66 RUNTIME_ASSERT(obj->Is##Type()); \
67 Type* name = Type::cast(obj);
68
69#define CONVERT_ARG_CHECKED(Type, name, index) \
70 RUNTIME_ASSERT(args[index]->Is##Type()); \
71 Handle<Type> name = args.at<Type>(index);
72
kasper.lundbd3ec4e2008-07-09 11:06:54 +000073// Cast the given object to a boolean and store it in a variable with
74// the given name. If the object is not a boolean call IllegalOperation
75// and return.
76#define CONVERT_BOOLEAN_CHECKED(name, obj) \
77 RUNTIME_ASSERT(obj->IsBoolean()); \
78 bool name = (obj)->IsTrue();
79
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000080// Cast the given object to a Smi and store its value in an int variable
81// with the given name. If the object is not a Smi call IllegalOperation
82// and return.
83#define CONVERT_SMI_CHECKED(name, obj) \
84 RUNTIME_ASSERT(obj->IsSmi()); \
85 int name = Smi::cast(obj)->value();
86
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000087// Cast the given object to a double and store it in a variable with
88// the given name. If the object is not a number (as opposed to
89// the number not-a-number) call IllegalOperation and return.
90#define CONVERT_DOUBLE_CHECKED(name, obj) \
91 RUNTIME_ASSERT(obj->IsNumber()); \
92 double name = (obj)->Number();
93
94// Call the specified converter on the object *comand store the result in
95// a variable of the specified type with the given name. If the
96// object is not a Number call IllegalOperation and return.
97#define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \
98 RUNTIME_ASSERT(obj->IsNumber()); \
99 type name = NumberTo##Type(obj);
100
101// Non-reentrant string buffer for efficient general use in this file.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000102static StaticResource<StringInputBuffer> runtime_string_input_buffer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000103
104
lrn@chromium.org303ada72010-10-27 09:33:13 +0000105MUST_USE_RESULT static MaybeObject* DeepCopyBoilerplate(JSObject* boilerplate) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000106 StackLimitCheck check;
107 if (check.HasOverflowed()) return Top::StackOverflow();
108
lrn@chromium.org303ada72010-10-27 09:33:13 +0000109 Object* result;
110 { MaybeObject* maybe_result = Heap::CopyJSObject(boilerplate);
111 if (!maybe_result->ToObject(&result)) return maybe_result;
112 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000113 JSObject* copy = JSObject::cast(result);
114
115 // Deep copy local properties.
116 if (copy->HasFastProperties()) {
117 FixedArray* properties = copy->properties();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000118 for (int i = 0; i < properties->length(); i++) {
119 Object* value = properties->get(i);
120 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000121 JSObject* js_object = JSObject::cast(value);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000122 { MaybeObject* maybe_result = DeepCopyBoilerplate(js_object);
123 if (!maybe_result->ToObject(&result)) return maybe_result;
124 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000125 properties->set(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000126 }
127 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000128 int nof = copy->map()->inobject_properties();
129 for (int i = 0; i < nof; i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000130 Object* value = copy->InObjectPropertyAt(i);
131 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000132 JSObject* js_object = JSObject::cast(value);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000133 { MaybeObject* maybe_result = DeepCopyBoilerplate(js_object);
134 if (!maybe_result->ToObject(&result)) return maybe_result;
135 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000136 copy->InObjectPropertyAtPut(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000137 }
138 }
139 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000140 { MaybeObject* maybe_result =
141 Heap::AllocateFixedArray(copy->NumberOfLocalProperties(NONE));
142 if (!maybe_result->ToObject(&result)) return maybe_result;
143 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000144 FixedArray* names = FixedArray::cast(result);
145 copy->GetLocalPropertyNames(names, 0);
146 for (int i = 0; i < names->length(); i++) {
147 ASSERT(names->get(i)->IsString());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000148 String* key_string = String::cast(names->get(i));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000149 PropertyAttributes attributes =
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000150 copy->GetLocalPropertyAttribute(key_string);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000151 // Only deep copy fields from the object literal expression.
152 // In particular, don't try to copy the length attribute of
153 // an array.
154 if (attributes != NONE) continue;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000155 Object* value =
156 copy->GetProperty(key_string, &attributes)->ToObjectUnchecked();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000157 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000158 JSObject* js_object = JSObject::cast(value);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000159 { MaybeObject* maybe_result = DeepCopyBoilerplate(js_object);
160 if (!maybe_result->ToObject(&result)) return maybe_result;
161 }
162 { MaybeObject* maybe_result =
163 copy->SetProperty(key_string, result, NONE);
164 if (!maybe_result->ToObject(&result)) return maybe_result;
165 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000166 }
167 }
168 }
169
170 // Deep copy local elements.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000171 // Pixel elements cannot be created using an object literal.
ager@chromium.org3811b432009-10-28 14:53:37 +0000172 ASSERT(!copy->HasPixelElements() && !copy->HasExternalArrayElements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000173 switch (copy->GetElementsKind()) {
174 case JSObject::FAST_ELEMENTS: {
175 FixedArray* elements = FixedArray::cast(copy->elements());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000176 if (elements->map() == Heap::fixed_cow_array_map()) {
177 Counters::cow_arrays_created_runtime.Increment();
178#ifdef DEBUG
179 for (int i = 0; i < elements->length(); i++) {
180 ASSERT(!elements->get(i)->IsJSObject());
181 }
182#endif
183 } else {
184 for (int i = 0; i < elements->length(); i++) {
185 Object* value = elements->get(i);
186 if (value->IsJSObject()) {
187 JSObject* js_object = JSObject::cast(value);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000188 { MaybeObject* maybe_result = DeepCopyBoilerplate(js_object);
189 if (!maybe_result->ToObject(&result)) return maybe_result;
190 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000191 elements->set(i, result);
192 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000193 }
194 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000195 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000196 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000197 case JSObject::DICTIONARY_ELEMENTS: {
198 NumberDictionary* element_dictionary = copy->element_dictionary();
199 int capacity = element_dictionary->Capacity();
200 for (int i = 0; i < capacity; i++) {
201 Object* k = element_dictionary->KeyAt(i);
202 if (element_dictionary->IsKey(k)) {
203 Object* value = element_dictionary->ValueAt(i);
204 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000205 JSObject* js_object = JSObject::cast(value);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000206 { MaybeObject* maybe_result = DeepCopyBoilerplate(js_object);
207 if (!maybe_result->ToObject(&result)) return maybe_result;
208 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000209 element_dictionary->ValueAtPut(i, result);
210 }
211 }
212 }
213 break;
214 }
215 default:
216 UNREACHABLE();
217 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000218 }
219 return copy;
220}
221
222
lrn@chromium.org303ada72010-10-27 09:33:13 +0000223static MaybeObject* Runtime_CloneLiteralBoilerplate(Arguments args) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000224 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
225 return DeepCopyBoilerplate(boilerplate);
226}
227
228
lrn@chromium.org303ada72010-10-27 09:33:13 +0000229static MaybeObject* Runtime_CloneShallowLiteralBoilerplate(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000230 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000231 return Heap::CopyJSObject(boilerplate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000232}
233
234
ager@chromium.org236ad962008-09-25 09:45:57 +0000235static Handle<Map> ComputeObjectLiteralMap(
236 Handle<Context> context,
237 Handle<FixedArray> constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000238 bool* is_result_from_cache) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000239 int properties_length = constant_properties->length();
240 int number_of_properties = properties_length / 2;
ager@chromium.org236ad962008-09-25 09:45:57 +0000241 if (FLAG_canonicalize_object_literal_maps) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000242 // Check that there are only symbols and array indices among keys.
ager@chromium.org236ad962008-09-25 09:45:57 +0000243 int number_of_symbol_keys = 0;
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000244 for (int p = 0; p != properties_length; p += 2) {
245 Object* key = constant_properties->get(p);
246 uint32_t element_index = 0;
247 if (key->IsSymbol()) {
248 number_of_symbol_keys++;
249 } else if (key->ToArrayIndex(&element_index)) {
250 // An index key does not require space in the property backing store.
251 number_of_properties--;
252 } else {
253 // Bail out as a non-symbol non-index key makes caching impossible.
254 // ASSERT to make sure that the if condition after the loop is false.
255 ASSERT(number_of_symbol_keys != number_of_properties);
256 break;
257 }
ager@chromium.org236ad962008-09-25 09:45:57 +0000258 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000259 // If we only have symbols and array indices among keys then we can
260 // use the map cache in the global context.
ager@chromium.org236ad962008-09-25 09:45:57 +0000261 const int kMaxKeys = 10;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000262 if ((number_of_symbol_keys == number_of_properties) &&
263 (number_of_symbol_keys < kMaxKeys)) {
ager@chromium.org236ad962008-09-25 09:45:57 +0000264 // Create the fixed array with the key.
265 Handle<FixedArray> keys = Factory::NewFixedArray(number_of_symbol_keys);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000266 if (number_of_symbol_keys > 0) {
267 int index = 0;
268 for (int p = 0; p < properties_length; p += 2) {
269 Object* key = constant_properties->get(p);
270 if (key->IsSymbol()) {
271 keys->set(index++, key);
272 }
273 }
274 ASSERT(index == number_of_symbol_keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000275 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000276 *is_result_from_cache = true;
ager@chromium.org236ad962008-09-25 09:45:57 +0000277 return Factory::ObjectLiteralMapFromCache(context, keys);
278 }
279 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000280 *is_result_from_cache = false;
ager@chromium.org32912102009-01-16 10:38:43 +0000281 return Factory::CopyMap(
282 Handle<Map>(context->object_function()->initial_map()),
283 number_of_properties);
ager@chromium.org236ad962008-09-25 09:45:57 +0000284}
285
286
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000287static Handle<Object> CreateLiteralBoilerplate(
288 Handle<FixedArray> literals,
289 Handle<FixedArray> constant_properties);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000290
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000291
292static Handle<Object> CreateObjectLiteralBoilerplate(
293 Handle<FixedArray> literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000294 Handle<FixedArray> constant_properties,
295 bool should_have_fast_elements) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000296 // Get the global context from the literals array. This is the
297 // context in which the function was created and we use the object
298 // function from this context to create the object literal. We do
299 // not use the object function from the current global context
300 // because this might be the object function from another context
301 // which we should not have access to.
ager@chromium.org236ad962008-09-25 09:45:57 +0000302 Handle<Context> context =
303 Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals));
304
305 bool is_result_from_cache;
306 Handle<Map> map = ComputeObjectLiteralMap(context,
307 constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000308 &is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000309
ager@chromium.org236ad962008-09-25 09:45:57 +0000310 Handle<JSObject> boilerplate = Factory::NewJSObjectFromMap(map);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000311
312 // Normalize the elements of the boilerplate to save space if needed.
313 if (!should_have_fast_elements) NormalizeElements(boilerplate);
314
ager@chromium.org32912102009-01-16 10:38:43 +0000315 { // Add the constant properties to the boilerplate.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000316 int length = constant_properties->length();
ager@chromium.org236ad962008-09-25 09:45:57 +0000317 OptimizedObjectForAddingMultipleProperties opt(boilerplate,
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000318 length / 2,
ager@chromium.org236ad962008-09-25 09:45:57 +0000319 !is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000320 for (int index = 0; index < length; index +=2) {
321 Handle<Object> key(constant_properties->get(index+0));
322 Handle<Object> value(constant_properties->get(index+1));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000323 if (value->IsFixedArray()) {
324 // The value contains the constant_properties of a
325 // simple object literal.
326 Handle<FixedArray> array = Handle<FixedArray>::cast(value);
327 value = CreateLiteralBoilerplate(literals, array);
328 if (value.is_null()) return value;
329 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000330 Handle<Object> result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000331 uint32_t element_index = 0;
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000332 if (key->IsSymbol()) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000333 if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) {
334 // Array index as string (uint32).
335 result = SetOwnElement(boilerplate, element_index, value);
336 } else {
337 Handle<String> name(String::cast(*key));
338 ASSERT(!name->AsArrayIndex(&element_index));
339 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
340 value, NONE);
341 }
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000342 } else if (key->ToArrayIndex(&element_index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000343 // Array index (uint32).
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000344 result = SetOwnElement(boilerplate, element_index, value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000345 } else {
346 // Non-uint32 number.
347 ASSERT(key->IsNumber());
348 double num = key->Number();
349 char arr[100];
350 Vector<char> buffer(arr, ARRAY_SIZE(arr));
351 const char* str = DoubleToCString(num, buffer);
352 Handle<String> name = Factory::NewStringFromAscii(CStrVector(str));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000353 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
354 value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000355 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000356 // If setting the property on the boilerplate throws an
357 // exception, the exception is converted to an empty handle in
358 // the handle based operations. In that case, we need to
359 // convert back to an exception.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000360 if (result.is_null()) return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000361 }
362 }
363
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000364 return boilerplate;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000365}
366
367
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000368static Handle<Object> CreateArrayLiteralBoilerplate(
369 Handle<FixedArray> literals,
370 Handle<FixedArray> elements) {
371 // Create the JSArray.
372 Handle<JSFunction> constructor(
373 JSFunction::GlobalContextFromLiterals(*literals)->array_function());
374 Handle<Object> object = Factory::NewJSObject(constructor);
375
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000376 const bool is_cow = (elements->map() == Heap::fixed_cow_array_map());
377 Handle<FixedArray> copied_elements =
378 is_cow ? elements : Factory::CopyFixedArray(elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000379
380 Handle<FixedArray> content = Handle<FixedArray>::cast(copied_elements);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000381 if (is_cow) {
382#ifdef DEBUG
383 // Copy-on-write arrays must be shallow (and simple).
384 for (int i = 0; i < content->length(); i++) {
385 ASSERT(!content->get(i)->IsFixedArray());
386 }
387#endif
388 } else {
389 for (int i = 0; i < content->length(); i++) {
390 if (content->get(i)->IsFixedArray()) {
391 // The value contains the constant_properties of a
392 // simple object literal.
393 Handle<FixedArray> fa(FixedArray::cast(content->get(i)));
394 Handle<Object> result =
395 CreateLiteralBoilerplate(literals, fa);
396 if (result.is_null()) return result;
397 content->set(i, *result);
398 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000399 }
400 }
401
402 // Set the elements.
403 Handle<JSArray>::cast(object)->SetContent(*content);
404 return object;
405}
406
407
408static Handle<Object> CreateLiteralBoilerplate(
409 Handle<FixedArray> literals,
410 Handle<FixedArray> array) {
411 Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
412 switch (CompileTimeValue::GetType(array)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000413 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
414 return CreateObjectLiteralBoilerplate(literals, elements, true);
415 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
416 return CreateObjectLiteralBoilerplate(literals, elements, false);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000417 case CompileTimeValue::ARRAY_LITERAL:
418 return CreateArrayLiteralBoilerplate(literals, elements);
419 default:
420 UNREACHABLE();
421 return Handle<Object>::null();
422 }
423}
424
425
lrn@chromium.org303ada72010-10-27 09:33:13 +0000426static MaybeObject* Runtime_CreateArrayLiteralBoilerplate(Arguments args) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000427 // Takes a FixedArray of elements containing the literal elements of
428 // the array literal and produces JSArray with those elements.
429 // Additionally takes the literals array of the surrounding function
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000430 // which contains the context from which to get the Array function
431 // to use for creating the array literal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000432 HandleScope scope;
433 ASSERT(args.length() == 3);
434 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
435 CONVERT_SMI_CHECKED(literals_index, args[1]);
436 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000437
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000438 Handle<Object> object = CreateArrayLiteralBoilerplate(literals, elements);
439 if (object.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000440
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000441 // Update the functions literal and return the boilerplate.
442 literals->set(literals_index, *object);
443 return *object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000444}
445
446
lrn@chromium.org303ada72010-10-27 09:33:13 +0000447static MaybeObject* Runtime_CreateObjectLiteral(Arguments args) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000448 HandleScope scope;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000449 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000450 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
451 CONVERT_SMI_CHECKED(literals_index, args[1]);
452 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000453 CONVERT_SMI_CHECKED(fast_elements, args[3]);
454 bool should_have_fast_elements = fast_elements == 1;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000455
456 // Check if boilerplate exists. If not, create it first.
457 Handle<Object> boilerplate(literals->get(literals_index));
458 if (*boilerplate == Heap::undefined_value()) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000459 boilerplate = CreateObjectLiteralBoilerplate(literals,
460 constant_properties,
461 should_have_fast_elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000462 if (boilerplate.is_null()) return Failure::Exception();
463 // Update the functions literal and return the boilerplate.
464 literals->set(literals_index, *boilerplate);
465 }
466 return DeepCopyBoilerplate(JSObject::cast(*boilerplate));
467}
468
469
lrn@chromium.org303ada72010-10-27 09:33:13 +0000470static MaybeObject* Runtime_CreateObjectLiteralShallow(Arguments args) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000471 HandleScope scope;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000472 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000473 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
474 CONVERT_SMI_CHECKED(literals_index, args[1]);
475 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000476 CONVERT_SMI_CHECKED(fast_elements, args[3]);
477 bool should_have_fast_elements = fast_elements == 1;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000478
479 // Check if boilerplate exists. If not, create it first.
480 Handle<Object> boilerplate(literals->get(literals_index));
481 if (*boilerplate == Heap::undefined_value()) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000482 boilerplate = CreateObjectLiteralBoilerplate(literals,
483 constant_properties,
484 should_have_fast_elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000485 if (boilerplate.is_null()) return Failure::Exception();
486 // Update the functions literal and return the boilerplate.
487 literals->set(literals_index, *boilerplate);
488 }
489 return Heap::CopyJSObject(JSObject::cast(*boilerplate));
490}
491
492
lrn@chromium.org303ada72010-10-27 09:33:13 +0000493static MaybeObject* Runtime_CreateArrayLiteral(Arguments args) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000494 HandleScope scope;
495 ASSERT(args.length() == 3);
496 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
497 CONVERT_SMI_CHECKED(literals_index, args[1]);
498 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
499
500 // Check if boilerplate exists. If not, create it first.
501 Handle<Object> boilerplate(literals->get(literals_index));
502 if (*boilerplate == Heap::undefined_value()) {
503 boilerplate = CreateArrayLiteralBoilerplate(literals, elements);
504 if (boilerplate.is_null()) return Failure::Exception();
505 // Update the functions literal and return the boilerplate.
506 literals->set(literals_index, *boilerplate);
507 }
508 return DeepCopyBoilerplate(JSObject::cast(*boilerplate));
509}
510
511
lrn@chromium.org303ada72010-10-27 09:33:13 +0000512static MaybeObject* Runtime_CreateArrayLiteralShallow(Arguments args) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000513 HandleScope scope;
514 ASSERT(args.length() == 3);
515 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
516 CONVERT_SMI_CHECKED(literals_index, args[1]);
517 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
518
519 // Check if boilerplate exists. If not, create it first.
520 Handle<Object> boilerplate(literals->get(literals_index));
521 if (*boilerplate == Heap::undefined_value()) {
522 boilerplate = CreateArrayLiteralBoilerplate(literals, elements);
523 if (boilerplate.is_null()) return Failure::Exception();
524 // Update the functions literal and return the boilerplate.
525 literals->set(literals_index, *boilerplate);
526 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000527 if (JSObject::cast(*boilerplate)->elements()->map() ==
528 Heap::fixed_cow_array_map()) {
529 Counters::cow_arrays_created_runtime.Increment();
530 }
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000531 return Heap::CopyJSObject(JSObject::cast(*boilerplate));
532}
533
534
lrn@chromium.org303ada72010-10-27 09:33:13 +0000535static MaybeObject* Runtime_CreateCatchExtensionObject(Arguments args) {
ager@chromium.org32912102009-01-16 10:38:43 +0000536 ASSERT(args.length() == 2);
537 CONVERT_CHECKED(String, key, args[0]);
538 Object* value = args[1];
539 // Create a catch context extension object.
540 JSFunction* constructor =
541 Top::context()->global_context()->context_extension_function();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000542 Object* object;
543 { MaybeObject* maybe_object = Heap::AllocateJSObject(constructor);
544 if (!maybe_object->ToObject(&object)) return maybe_object;
545 }
ager@chromium.org32912102009-01-16 10:38:43 +0000546 // Assign the exception value to the catch variable and make sure
547 // that the catch variable is DontDelete.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000548 { MaybeObject* maybe_value =
549 JSObject::cast(object)->SetProperty(key, value, DONT_DELETE);
550 if (!maybe_value->ToObject(&value)) return maybe_value;
551 }
ager@chromium.org32912102009-01-16 10:38:43 +0000552 return object;
553}
554
555
lrn@chromium.org303ada72010-10-27 09:33:13 +0000556static MaybeObject* Runtime_ClassOf(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000557 NoHandleAllocation ha;
558 ASSERT(args.length() == 1);
559 Object* obj = args[0];
560 if (!obj->IsJSObject()) return Heap::null_value();
561 return JSObject::cast(obj)->class_name();
562}
563
ager@chromium.org7c537e22008-10-16 08:43:32 +0000564
lrn@chromium.org303ada72010-10-27 09:33:13 +0000565static MaybeObject* Runtime_IsInPrototypeChain(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000566 NoHandleAllocation ha;
567 ASSERT(args.length() == 2);
568 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
569 Object* O = args[0];
570 Object* V = args[1];
571 while (true) {
572 Object* prototype = V->GetPrototype();
573 if (prototype->IsNull()) return Heap::false_value();
574 if (O == prototype) return Heap::true_value();
575 V = prototype;
576 }
577}
578
579
ager@chromium.org9085a012009-05-11 19:22:57 +0000580// Inserts an object as the hidden prototype of another object.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000581static MaybeObject* Runtime_SetHiddenPrototype(Arguments args) {
ager@chromium.org9085a012009-05-11 19:22:57 +0000582 NoHandleAllocation ha;
583 ASSERT(args.length() == 2);
584 CONVERT_CHECKED(JSObject, jsobject, args[0]);
585 CONVERT_CHECKED(JSObject, proto, args[1]);
586
587 // Sanity checks. The old prototype (that we are replacing) could
588 // theoretically be null, but if it is not null then check that we
589 // didn't already install a hidden prototype here.
590 RUNTIME_ASSERT(!jsobject->GetPrototype()->IsHeapObject() ||
591 !HeapObject::cast(jsobject->GetPrototype())->map()->is_hidden_prototype());
592 RUNTIME_ASSERT(!proto->map()->is_hidden_prototype());
593
594 // Allocate up front before we start altering state in case we get a GC.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000595 Object* map_or_failure;
596 { MaybeObject* maybe_map_or_failure = proto->map()->CopyDropTransitions();
597 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
598 return maybe_map_or_failure;
599 }
600 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000601 Map* new_proto_map = Map::cast(map_or_failure);
602
lrn@chromium.org303ada72010-10-27 09:33:13 +0000603 { MaybeObject* maybe_map_or_failure = jsobject->map()->CopyDropTransitions();
604 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
605 return maybe_map_or_failure;
606 }
607 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000608 Map* new_map = Map::cast(map_or_failure);
609
610 // Set proto's prototype to be the old prototype of the object.
611 new_proto_map->set_prototype(jsobject->GetPrototype());
612 proto->set_map(new_proto_map);
613 new_proto_map->set_is_hidden_prototype();
614
615 // Set the object's prototype to proto.
616 new_map->set_prototype(proto);
617 jsobject->set_map(new_map);
618
619 return Heap::undefined_value();
620}
621
622
lrn@chromium.org303ada72010-10-27 09:33:13 +0000623static MaybeObject* Runtime_IsConstructCall(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000624 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +0000625 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000626 JavaScriptFrameIterator it;
627 return Heap::ToBoolean(it.frame()->IsConstructor());
628}
629
630
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000631// Recursively traverses hidden prototypes if property is not found
632static void GetOwnPropertyImplementation(JSObject* obj,
633 String* name,
634 LookupResult* result) {
635 obj->LocalLookupRealNamedProperty(name, result);
636
637 if (!result->IsProperty()) {
638 Object* proto = obj->GetPrototype();
639 if (proto->IsJSObject() &&
640 JSObject::cast(proto)->map()->is_hidden_prototype())
641 GetOwnPropertyImplementation(JSObject::cast(proto),
642 name, result);
643 }
644}
645
646
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000647// Enumerator used as indices into the array returned from GetOwnProperty
648enum PropertyDescriptorIndices {
649 IS_ACCESSOR_INDEX,
650 VALUE_INDEX,
651 GETTER_INDEX,
652 SETTER_INDEX,
653 WRITABLE_INDEX,
654 ENUMERABLE_INDEX,
655 CONFIGURABLE_INDEX,
656 DESCRIPTOR_SIZE
657};
658
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000659// Returns an array with the property description:
660// if args[1] is not a property on args[0]
661// returns undefined
662// if args[1] is a data property on args[0]
663// [false, value, Writeable, Enumerable, Configurable]
664// if args[1] is an accessor on args[0]
665// [true, GetFunction, SetFunction, Enumerable, Configurable]
lrn@chromium.org303ada72010-10-27 09:33:13 +0000666static MaybeObject* Runtime_GetOwnProperty(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000667 ASSERT(args.length() == 2);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000668 HandleScope scope;
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000669 Handle<FixedArray> elms = Factory::NewFixedArray(DESCRIPTOR_SIZE);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000670 Handle<JSArray> desc = Factory::NewJSArrayWithElements(elms);
671 LookupResult result;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000672 CONVERT_ARG_CHECKED(JSObject, obj, 0);
673 CONVERT_ARG_CHECKED(String, name, 1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000674
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000675 // This could be an element.
676 uint32_t index;
677 if (name->AsArrayIndex(&index)) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000678 switch (obj->HasLocalElement(index)) {
679 case JSObject::UNDEFINED_ELEMENT:
680 return Heap::undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000681
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000682 case JSObject::STRING_CHARACTER_ELEMENT: {
683 // Special handling of string objects according to ECMAScript 5
684 // 15.5.5.2. Note that this might be a string object with elements
685 // other than the actual string value. This is covered by the
686 // subsequent cases.
687 Handle<JSValue> js_value = Handle<JSValue>::cast(obj);
688 Handle<String> str(String::cast(js_value->value()));
689 Handle<String> substr = SubString(str, index, index+1, NOT_TENURED);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000690
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000691 elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
692 elms->set(VALUE_INDEX, *substr);
693 elms->set(WRITABLE_INDEX, Heap::false_value());
694 elms->set(ENUMERABLE_INDEX, Heap::false_value());
695 elms->set(CONFIGURABLE_INDEX, Heap::false_value());
696 return *desc;
697 }
698
699 case JSObject::INTERCEPTED_ELEMENT:
700 case JSObject::FAST_ELEMENT: {
701 elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
702 Handle<Object> element = GetElement(Handle<Object>(obj), index);
703 elms->set(VALUE_INDEX, *element);
704 elms->set(WRITABLE_INDEX, Heap::true_value());
705 elms->set(ENUMERABLE_INDEX, Heap::true_value());
706 elms->set(CONFIGURABLE_INDEX, Heap::true_value());
707 return *desc;
708 }
709
710 case JSObject::DICTIONARY_ELEMENT: {
711 NumberDictionary* dictionary = obj->element_dictionary();
712 int entry = dictionary->FindEntry(index);
713 ASSERT(entry != NumberDictionary::kNotFound);
714 PropertyDetails details = dictionary->DetailsAt(entry);
715 switch (details.type()) {
716 case CALLBACKS: {
717 // This is an accessor property with getter and/or setter.
718 FixedArray* callbacks =
719 FixedArray::cast(dictionary->ValueAt(entry));
720 elms->set(IS_ACCESSOR_INDEX, Heap::true_value());
721 elms->set(GETTER_INDEX, callbacks->get(0));
722 elms->set(SETTER_INDEX, callbacks->get(1));
723 break;
724 }
725 case NORMAL:
726 // This is a data property.
727 elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
728 elms->set(VALUE_INDEX, dictionary->ValueAt(entry));
729 elms->set(WRITABLE_INDEX, Heap::ToBoolean(!details.IsReadOnly()));
730 break;
731 default:
732 UNREACHABLE();
733 break;
734 }
735 elms->set(ENUMERABLE_INDEX, Heap::ToBoolean(!details.IsDontEnum()));
736 elms->set(CONFIGURABLE_INDEX, Heap::ToBoolean(!details.IsDontDelete()));
737 return *desc;
738 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000739 }
740 }
741
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000742 // Use recursive implementation to also traverse hidden prototypes
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000743 GetOwnPropertyImplementation(*obj, *name, &result);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000744
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000745 if (!result.IsProperty()) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000746 return Heap::undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000747 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000748
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000749 elms->set(ENUMERABLE_INDEX, Heap::ToBoolean(!result.IsDontEnum()));
750 elms->set(CONFIGURABLE_INDEX, Heap::ToBoolean(!result.IsDontDelete()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000751
752 bool is_js_accessor = (result.type() == CALLBACKS) &&
753 (result.GetCallbackObject()->IsFixedArray());
754
755 if (is_js_accessor) {
756 // __defineGetter__/__defineSetter__ callback.
757 FixedArray* structure = FixedArray::cast(result.GetCallbackObject());
758 elms->set(IS_ACCESSOR_INDEX, Heap::true_value());
759 elms->set(GETTER_INDEX, structure->get(0));
760 elms->set(SETTER_INDEX, structure->get(1));
761 } else {
762 elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
763 elms->set(WRITABLE_INDEX, Heap::ToBoolean(!result.IsReadOnly()));
764
765 PropertyAttributes attrs;
766 Object* value;
767 { MaybeObject* maybe_value = obj->GetProperty(*obj, &result, *name, &attrs);
768 if (!maybe_value->ToObject(&value)) return maybe_value;
769 }
770 elms->set(VALUE_INDEX, value);
771 }
772
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000773 return *desc;
774}
775
776
lrn@chromium.org303ada72010-10-27 09:33:13 +0000777static MaybeObject* Runtime_PreventExtensions(Arguments args) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000778 ASSERT(args.length() == 1);
779 CONVERT_CHECKED(JSObject, obj, args[0]);
780 return obj->PreventExtensions();
781}
782
lrn@chromium.org303ada72010-10-27 09:33:13 +0000783static MaybeObject* Runtime_IsExtensible(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000784 ASSERT(args.length() == 1);
785 CONVERT_CHECKED(JSObject, obj, args[0]);
786 return obj->map()->is_extensible() ? Heap::true_value()
787 : Heap::false_value();
788}
789
790
lrn@chromium.org303ada72010-10-27 09:33:13 +0000791static MaybeObject* Runtime_RegExpCompile(Arguments args) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000792 HandleScope scope;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000793 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000794 CONVERT_ARG_CHECKED(JSRegExp, re, 0);
795 CONVERT_ARG_CHECKED(String, pattern, 1);
796 CONVERT_ARG_CHECKED(String, flags, 2);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000797 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags);
798 if (result.is_null()) return Failure::Exception();
799 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000800}
801
802
lrn@chromium.org303ada72010-10-27 09:33:13 +0000803static MaybeObject* Runtime_CreateApiFunction(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000804 HandleScope scope;
805 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000806 CONVERT_ARG_CHECKED(FunctionTemplateInfo, data, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000807 return *Factory::CreateApiFunction(data);
808}
809
810
lrn@chromium.org303ada72010-10-27 09:33:13 +0000811static MaybeObject* Runtime_IsTemplate(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000812 ASSERT(args.length() == 1);
813 Object* arg = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000814 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000815 return Heap::ToBoolean(result);
816}
817
818
lrn@chromium.org303ada72010-10-27 09:33:13 +0000819static MaybeObject* Runtime_GetTemplateField(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000820 ASSERT(args.length() == 2);
821 CONVERT_CHECKED(HeapObject, templ, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000822 CONVERT_CHECKED(Smi, field, args[1]);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000823 int index = field->value();
824 int offset = index * kPointerSize + HeapObject::kHeaderSize;
825 InstanceType type = templ->map()->instance_type();
826 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
827 type == OBJECT_TEMPLATE_INFO_TYPE);
828 RUNTIME_ASSERT(offset > 0);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000829 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000830 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
831 } else {
832 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
833 }
834 return *HeapObject::RawField(templ, offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000835}
836
837
lrn@chromium.org303ada72010-10-27 09:33:13 +0000838static MaybeObject* Runtime_DisableAccessChecks(Arguments args) {
ager@chromium.org870a0b62008-11-04 11:43:05 +0000839 ASSERT(args.length() == 1);
840 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +0000841 Map* old_map = object->map();
842 bool needs_access_checks = old_map->is_access_check_needed();
843 if (needs_access_checks) {
844 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000845 Object* new_map;
846 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
847 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
848 }
ager@chromium.org32912102009-01-16 10:38:43 +0000849
850 Map::cast(new_map)->set_is_access_check_needed(false);
851 object->set_map(Map::cast(new_map));
852 }
ager@chromium.org870a0b62008-11-04 11:43:05 +0000853 return needs_access_checks ? Heap::true_value() : Heap::false_value();
854}
855
856
lrn@chromium.org303ada72010-10-27 09:33:13 +0000857static MaybeObject* Runtime_EnableAccessChecks(Arguments args) {
ager@chromium.org870a0b62008-11-04 11:43:05 +0000858 ASSERT(args.length() == 1);
859 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +0000860 Map* old_map = object->map();
861 if (!old_map->is_access_check_needed()) {
862 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000863 Object* new_map;
864 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
865 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
866 }
ager@chromium.org32912102009-01-16 10:38:43 +0000867
868 Map::cast(new_map)->set_is_access_check_needed(true);
869 object->set_map(Map::cast(new_map));
870 }
ager@chromium.org870a0b62008-11-04 11:43:05 +0000871 return Heap::undefined_value();
872}
873
874
lrn@chromium.org303ada72010-10-27 09:33:13 +0000875static Failure* ThrowRedeclarationError(const char* type, Handle<String> name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000876 HandleScope scope;
877 Handle<Object> type_handle = Factory::NewStringFromAscii(CStrVector(type));
878 Handle<Object> args[2] = { type_handle, name };
879 Handle<Object> error =
880 Factory::NewTypeError("redeclaration", HandleVector(args, 2));
881 return Top::Throw(*error);
882}
883
884
lrn@chromium.org303ada72010-10-27 09:33:13 +0000885static MaybeObject* Runtime_DeclareGlobals(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000886 HandleScope scope;
887 Handle<GlobalObject> global = Handle<GlobalObject>(Top::context()->global());
888
ager@chromium.org3811b432009-10-28 14:53:37 +0000889 Handle<Context> context = args.at<Context>(0);
890 CONVERT_ARG_CHECKED(FixedArray, pairs, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000891 bool is_eval = Smi::cast(args[2])->value() == 1;
892
893 // Compute the property attributes. According to ECMA-262, section
894 // 13, page 71, the property must be read-only and
895 // non-deletable. However, neither SpiderMonkey nor KJS creates the
896 // property as read-only, so we don't either.
897 PropertyAttributes base = is_eval ? NONE : DONT_DELETE;
898
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000899 // Traverse the name/value pairs and set the properties.
900 int length = pairs->length();
901 for (int i = 0; i < length; i += 2) {
902 HandleScope scope;
903 Handle<String> name(String::cast(pairs->get(i)));
904 Handle<Object> value(pairs->get(i + 1));
905
906 // We have to declare a global const property. To capture we only
907 // assign to it when evaluating the assignment for "const x =
908 // <expr>" the initial value is the hole.
909 bool is_const_property = value->IsTheHole();
910
911 if (value->IsUndefined() || is_const_property) {
912 // Lookup the property in the global object, and don't set the
913 // value of the variable if the property is already there.
914 LookupResult lookup;
915 global->Lookup(*name, &lookup);
916 if (lookup.IsProperty()) {
917 // Determine if the property is local by comparing the holder
918 // against the global object. The information will be used to
919 // avoid throwing re-declaration errors when declaring
920 // variables or constants that exist in the prototype chain.
921 bool is_local = (*global == lookup.holder());
922 // Get the property attributes and determine if the property is
923 // read-only.
924 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
925 bool is_read_only = (attributes & READ_ONLY) != 0;
926 if (lookup.type() == INTERCEPTOR) {
927 // If the interceptor says the property is there, we
928 // just return undefined without overwriting the property.
929 // Otherwise, we continue to setting the property.
930 if (attributes != ABSENT) {
931 // Check if the existing property conflicts with regards to const.
932 if (is_local && (is_read_only || is_const_property)) {
933 const char* type = (is_read_only) ? "const" : "var";
934 return ThrowRedeclarationError(type, name);
935 };
936 // The property already exists without conflicting: Go to
937 // the next declaration.
938 continue;
939 }
940 // Fall-through and introduce the absent property by using
941 // SetProperty.
942 } else {
943 if (is_local && (is_read_only || is_const_property)) {
944 const char* type = (is_read_only) ? "const" : "var";
945 return ThrowRedeclarationError(type, name);
946 }
947 // The property already exists without conflicting: Go to
948 // the next declaration.
949 continue;
950 }
951 }
952 } else {
953 // Copy the function and update its context. Use it as value.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000954 Handle<SharedFunctionInfo> shared =
955 Handle<SharedFunctionInfo>::cast(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000956 Handle<JSFunction> function =
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000957 Factory::NewFunctionFromSharedFunctionInfo(shared, context, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000958 value = function;
959 }
960
961 LookupResult lookup;
962 global->LocalLookup(*name, &lookup);
963
964 PropertyAttributes attributes = is_const_property
965 ? static_cast<PropertyAttributes>(base | READ_ONLY)
966 : base;
967
968 if (lookup.IsProperty()) {
969 // There's a local property that we need to overwrite because
970 // we're either declaring a function or there's an interceptor
971 // that claims the property is absent.
972
973 // Check for conflicting re-declarations. We cannot have
974 // conflicting types in case of intercepted properties because
975 // they are absent.
976 if (lookup.type() != INTERCEPTOR &&
977 (lookup.IsReadOnly() || is_const_property)) {
978 const char* type = (lookup.IsReadOnly()) ? "const" : "var";
979 return ThrowRedeclarationError(type, name);
980 }
981 SetProperty(global, name, value, attributes);
982 } else {
983 // If a property with this name does not already exist on the
984 // global object add the property locally. We take special
985 // precautions to always add it as a local property even in case
986 // of callbacks in the prototype chain (this rules out using
987 // SetProperty). Also, we must use the handle-based version to
988 // avoid GC issues.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000989 SetLocalPropertyIgnoreAttributes(global, name, value, attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000990 }
991 }
ager@chromium.org7c537e22008-10-16 08:43:32 +0000992
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000993 return Heap::undefined_value();
994}
995
996
lrn@chromium.org303ada72010-10-27 09:33:13 +0000997static MaybeObject* Runtime_DeclareContextSlot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000998 HandleScope scope;
ager@chromium.org7c537e22008-10-16 08:43:32 +0000999 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001000
ager@chromium.org7c537e22008-10-16 08:43:32 +00001001 CONVERT_ARG_CHECKED(Context, context, 0);
1002 Handle<String> name(String::cast(args[1]));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001003 PropertyAttributes mode =
ager@chromium.org7c537e22008-10-16 08:43:32 +00001004 static_cast<PropertyAttributes>(Smi::cast(args[2])->value());
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001005 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001006 Handle<Object> initial_value(args[3]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001007
1008 // Declarations are always done in the function context.
1009 context = Handle<Context>(context->fcontext());
1010
1011 int index;
1012 PropertyAttributes attributes;
1013 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001014 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001015 context->Lookup(name, flags, &index, &attributes);
1016
1017 if (attributes != ABSENT) {
1018 // The name was declared before; check for conflicting
1019 // re-declarations: This is similar to the code in parser.cc in
1020 // the AstBuildingParser::Declare function.
1021 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
1022 // Functions are not read-only.
1023 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
1024 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
1025 return ThrowRedeclarationError(type, name);
1026 }
1027
1028 // Initialize it if necessary.
1029 if (*initial_value != NULL) {
1030 if (index >= 0) {
1031 // The variable or constant context slot should always be in
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001032 // the function context or the arguments object.
1033 if (holder->IsContext()) {
1034 ASSERT(holder.is_identical_to(context));
1035 if (((attributes & READ_ONLY) == 0) ||
1036 context->get(index)->IsTheHole()) {
1037 context->set(index, *initial_value);
1038 }
1039 } else {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001040 // The holder is an arguments object.
1041 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
1042 SetElement(arguments, index, initial_value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001043 }
1044 } else {
1045 // Slow case: The property is not in the FixedArray part of the context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001046 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001047 SetProperty(context_ext, name, initial_value, mode);
1048 }
1049 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001050
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001051 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001052 // The property is not in the function context. It needs to be
1053 // "declared" in the function context's extension context, or in the
1054 // global context.
1055 Handle<JSObject> context_ext;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001056 if (context->has_extension()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001057 // The function context's extension context exists - use it.
1058 context_ext = Handle<JSObject>(context->extension());
1059 } else {
1060 // The function context's extension context does not exists - allocate
1061 // it.
1062 context_ext = Factory::NewJSObject(Top::context_extension_function());
1063 // And store it in the extension slot.
1064 context->set_extension(*context_ext);
1065 }
1066 ASSERT(*context_ext != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001067
ager@chromium.org7c537e22008-10-16 08:43:32 +00001068 // Declare the property by setting it to the initial value if provided,
1069 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
1070 // constant declarations).
1071 ASSERT(!context_ext->HasLocalProperty(*name));
1072 Handle<Object> value(Heap::undefined_value());
1073 if (*initial_value != NULL) value = initial_value;
1074 SetProperty(context_ext, name, value, mode);
1075 ASSERT(context_ext->GetLocalPropertyAttribute(*name) == mode);
1076 }
1077
1078 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001079}
1080
1081
lrn@chromium.org303ada72010-10-27 09:33:13 +00001082static MaybeObject* Runtime_InitializeVarGlobal(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001083 NoHandleAllocation nha;
1084
1085 // Determine if we need to assign to the variable if it already
1086 // exists (based on the number of arguments).
1087 RUNTIME_ASSERT(args.length() == 1 || args.length() == 2);
1088 bool assign = args.length() == 2;
1089
1090 CONVERT_ARG_CHECKED(String, name, 0);
1091 GlobalObject* global = Top::context()->global();
1092
1093 // According to ECMA-262, section 12.2, page 62, the property must
1094 // not be deletable.
1095 PropertyAttributes attributes = DONT_DELETE;
1096
1097 // Lookup the property locally in the global object. If it isn't
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001098 // there, there is a property with this name in the prototype chain.
1099 // We follow Safari and Firefox behavior and only set the property
1100 // locally if there is an explicit initialization value that we have
1101 // to assign to the property. When adding the property we take
1102 // special precautions to always add it as a local property even in
1103 // case of callbacks in the prototype chain (this rules out using
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001104 // SetProperty). We have SetLocalPropertyIgnoreAttributes for
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001105 // this.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001106 // Note that objects can have hidden prototypes, so we need to traverse
1107 // the whole chain of hidden prototypes to do a 'local' lookup.
1108 JSObject* real_holder = global;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001109 LookupResult lookup;
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001110 while (true) {
1111 real_holder->LocalLookup(*name, &lookup);
1112 if (lookup.IsProperty()) {
1113 // Determine if this is a redeclaration of something read-only.
1114 if (lookup.IsReadOnly()) {
1115 // If we found readonly property on one of hidden prototypes,
1116 // just shadow it.
1117 if (real_holder != Top::context()->global()) break;
1118 return ThrowRedeclarationError("const", name);
1119 }
1120
1121 // Determine if this is a redeclaration of an intercepted read-only
1122 // property and figure out if the property exists at all.
1123 bool found = true;
1124 PropertyType type = lookup.type();
1125 if (type == INTERCEPTOR) {
1126 HandleScope handle_scope;
1127 Handle<JSObject> holder(real_holder);
1128 PropertyAttributes intercepted = holder->GetPropertyAttribute(*name);
1129 real_holder = *holder;
1130 if (intercepted == ABSENT) {
1131 // The interceptor claims the property isn't there. We need to
1132 // make sure to introduce it.
1133 found = false;
1134 } else if ((intercepted & READ_ONLY) != 0) {
1135 // The property is present, but read-only. Since we're trying to
1136 // overwrite it with a variable declaration we must throw a
1137 // re-declaration error. However if we found readonly property
1138 // on one of hidden prototypes, just shadow it.
1139 if (real_holder != Top::context()->global()) break;
1140 return ThrowRedeclarationError("const", name);
1141 }
1142 }
1143
1144 if (found && !assign) {
1145 // The global property is there and we're not assigning any value
1146 // to it. Just return.
1147 return Heap::undefined_value();
1148 }
1149
1150 // Assign the value (or undefined) to the property.
1151 Object* value = (assign) ? args[1] : Heap::undefined_value();
1152 return real_holder->SetProperty(&lookup, *name, value, attributes);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001153 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001154
1155 Object* proto = real_holder->GetPrototype();
1156 if (!proto->IsJSObject())
1157 break;
1158
1159 if (!JSObject::cast(proto)->map()->is_hidden_prototype())
1160 break;
1161
1162 real_holder = JSObject::cast(proto);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001163 }
1164
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001165 global = Top::context()->global();
1166 if (assign) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001167 return global->SetLocalPropertyIgnoreAttributes(*name,
1168 args[1],
1169 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001170 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001171 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001172}
1173
1174
lrn@chromium.org303ada72010-10-27 09:33:13 +00001175static MaybeObject* Runtime_InitializeConstGlobal(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001176 // All constants are declared with an initial value. The name
1177 // of the constant is the first argument and the initial value
1178 // is the second.
1179 RUNTIME_ASSERT(args.length() == 2);
1180 CONVERT_ARG_CHECKED(String, name, 0);
1181 Handle<Object> value = args.at<Object>(1);
1182
1183 // Get the current global object from top.
1184 GlobalObject* global = Top::context()->global();
1185
1186 // According to ECMA-262, section 12.2, page 62, the property must
1187 // not be deletable. Since it's a const, it must be READ_ONLY too.
1188 PropertyAttributes attributes =
1189 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
1190
1191 // Lookup the property locally in the global object. If it isn't
1192 // there, we add the property and take special precautions to always
1193 // add it as a local property even in case of callbacks in the
1194 // prototype chain (this rules out using SetProperty).
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001195 // We use SetLocalPropertyIgnoreAttributes instead
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001196 LookupResult lookup;
1197 global->LocalLookup(*name, &lookup);
1198 if (!lookup.IsProperty()) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001199 return global->SetLocalPropertyIgnoreAttributes(*name,
1200 *value,
1201 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001202 }
1203
1204 // Determine if this is a redeclaration of something not
1205 // read-only. In case the result is hidden behind an interceptor we
1206 // need to ask it for the property attributes.
1207 if (!lookup.IsReadOnly()) {
1208 if (lookup.type() != INTERCEPTOR) {
1209 return ThrowRedeclarationError("var", name);
1210 }
1211
1212 PropertyAttributes intercepted = global->GetPropertyAttribute(*name);
1213
1214 // Throw re-declaration error if the intercepted property is present
1215 // but not read-only.
1216 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
1217 return ThrowRedeclarationError("var", name);
1218 }
1219
1220 // Restore global object from context (in case of GC) and continue
1221 // with setting the value because the property is either absent or
1222 // read-only. We also have to do redo the lookup.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001223 HandleScope handle_scope;
1224 Handle<GlobalObject>global(Top::context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001225
1226 // BUG 1213579: Handle the case where we have to set a read-only
1227 // property through an interceptor and only do it if it's
1228 // uninitialized, e.g. the hole. Nirk...
lrn@chromium.org303ada72010-10-27 09:33:13 +00001229 SetProperty(global, name, value, attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001230 return *value;
1231 }
1232
1233 // Set the value, but only we're assigning the initial value to a
1234 // constant. For now, we determine this by checking if the
1235 // current value is the hole.
1236 PropertyType type = lookup.type();
1237 if (type == FIELD) {
1238 FixedArray* properties = global->properties();
1239 int index = lookup.GetFieldIndex();
1240 if (properties->get(index)->IsTheHole()) {
1241 properties->set(index, *value);
1242 }
1243 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001244 if (global->GetNormalizedProperty(&lookup)->IsTheHole()) {
1245 global->SetNormalizedProperty(&lookup, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001246 }
1247 } else {
1248 // Ignore re-initialization of constants that have already been
1249 // assigned a function value.
1250 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
1251 }
1252
1253 // Use the set value as the result of the operation.
1254 return *value;
1255}
1256
1257
lrn@chromium.org303ada72010-10-27 09:33:13 +00001258static MaybeObject* Runtime_InitializeConstContextSlot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001259 HandleScope scope;
1260 ASSERT(args.length() == 3);
1261
1262 Handle<Object> value(args[0]);
1263 ASSERT(!value->IsTheHole());
1264 CONVERT_ARG_CHECKED(Context, context, 1);
1265 Handle<String> name(String::cast(args[2]));
1266
1267 // Initializations are always done in the function context.
1268 context = Handle<Context>(context->fcontext());
1269
1270 int index;
1271 PropertyAttributes attributes;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001272 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001273 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001274 context->Lookup(name, flags, &index, &attributes);
1275
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001276 // In most situations, the property introduced by the const
1277 // declaration should be present in the context extension object.
1278 // However, because declaration and initialization are separate, the
1279 // property might have been deleted (if it was introduced by eval)
1280 // before we reach the initialization point.
1281 //
1282 // Example:
1283 //
1284 // function f() { eval("delete x; const x;"); }
1285 //
1286 // In that case, the initialization behaves like a normal assignment
1287 // to property 'x'.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001288 if (index >= 0) {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001289 // Property was found in a context.
1290 if (holder->IsContext()) {
1291 // The holder cannot be the function context. If it is, there
1292 // should have been a const redeclaration error when declaring
1293 // the const property.
1294 ASSERT(!holder.is_identical_to(context));
1295 if ((attributes & READ_ONLY) == 0) {
1296 Handle<Context>::cast(holder)->set(index, *value);
1297 }
1298 } else {
1299 // The holder is an arguments object.
1300 ASSERT((attributes & READ_ONLY) == 0);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001301 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
1302 SetElement(arguments, index, value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001303 }
1304 return *value;
1305 }
1306
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001307 // The property could not be found, we introduce it in the global
1308 // context.
1309 if (attributes == ABSENT) {
1310 Handle<JSObject> global = Handle<JSObject>(Top::context()->global());
1311 SetProperty(global, name, value, NONE);
1312 return *value;
1313 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001314
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001315 // The property was present in a context extension object.
1316 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001317
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001318 if (*context_ext == context->extension()) {
1319 // This is the property that was introduced by the const
1320 // declaration. Set it if it hasn't been set before. NOTE: We
1321 // cannot use GetProperty() to get the current value as it
1322 // 'unholes' the value.
1323 LookupResult lookup;
1324 context_ext->LocalLookupRealNamedProperty(*name, &lookup);
1325 ASSERT(lookup.IsProperty()); // the property was declared
1326 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
1327
1328 PropertyType type = lookup.type();
1329 if (type == FIELD) {
1330 FixedArray* properties = context_ext->properties();
1331 int index = lookup.GetFieldIndex();
1332 if (properties->get(index)->IsTheHole()) {
1333 properties->set(index, *value);
1334 }
1335 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001336 if (context_ext->GetNormalizedProperty(&lookup)->IsTheHole()) {
1337 context_ext->SetNormalizedProperty(&lookup, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001338 }
1339 } else {
1340 // We should not reach here. Any real, named property should be
1341 // either a field or a dictionary slot.
1342 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001343 }
1344 } else {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001345 // The property was found in a different context extension object.
1346 // Set it if it is not a read-only property.
1347 if ((attributes & READ_ONLY) == 0) {
1348 Handle<Object> set = SetProperty(context_ext, name, value, attributes);
1349 // Setting a property might throw an exception. Exceptions
1350 // are converted to empty handles in handle operations. We
1351 // need to convert back to exceptions here.
1352 if (set.is_null()) {
1353 ASSERT(Top::has_pending_exception());
1354 return Failure::Exception();
1355 }
1356 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001357 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001358
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001359 return *value;
1360}
1361
1362
lrn@chromium.org303ada72010-10-27 09:33:13 +00001363static MaybeObject* Runtime_OptimizeObjectForAddingMultipleProperties(
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001364 Arguments args) {
1365 HandleScope scope;
1366 ASSERT(args.length() == 2);
1367 CONVERT_ARG_CHECKED(JSObject, object, 0);
1368 CONVERT_SMI_CHECKED(properties, args[1]);
1369 if (object->HasFastProperties()) {
1370 NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
1371 }
1372 return *object;
1373}
1374
1375
lrn@chromium.org303ada72010-10-27 09:33:13 +00001376static MaybeObject* Runtime_RegExpExec(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001377 HandleScope scope;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001378 ASSERT(args.length() == 4);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001379 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
1380 CONVERT_ARG_CHECKED(String, subject, 1);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001381 // Due to the way the JS calls are constructed this must be less than the
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001382 // length of a string, i.e. it is always a Smi. We check anyway for security.
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001383 CONVERT_SMI_CHECKED(index, args[2]);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001384 CONVERT_ARG_CHECKED(JSArray, last_match_info, 3);
ager@chromium.org41826e72009-03-30 13:30:57 +00001385 RUNTIME_ASSERT(last_match_info->HasFastElements());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001386 RUNTIME_ASSERT(index >= 0);
1387 RUNTIME_ASSERT(index <= subject->length());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001388 Counters::regexp_entry_runtime.Increment();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001389 Handle<Object> result = RegExpImpl::Exec(regexp,
1390 subject,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001391 index,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001392 last_match_info);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001393 if (result.is_null()) return Failure::Exception();
1394 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001395}
1396
1397
lrn@chromium.org303ada72010-10-27 09:33:13 +00001398static MaybeObject* Runtime_RegExpConstructResult(Arguments args) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001399 ASSERT(args.length() == 3);
1400 CONVERT_SMI_CHECKED(elements_count, args[0]);
1401 if (elements_count > JSArray::kMaxFastElementsLength) {
1402 return Top::ThrowIllegalOperation();
1403 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00001404 Object* new_object;
1405 { MaybeObject* maybe_new_object =
1406 Heap::AllocateFixedArrayWithHoles(elements_count);
1407 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1408 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001409 FixedArray* elements = FixedArray::cast(new_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001410 { MaybeObject* maybe_new_object = Heap::AllocateRaw(JSRegExpResult::kSize,
1411 NEW_SPACE,
1412 OLD_POINTER_SPACE);
1413 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1414 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001415 {
1416 AssertNoAllocation no_gc;
1417 HandleScope scope;
1418 reinterpret_cast<HeapObject*>(new_object)->
1419 set_map(Top::global_context()->regexp_result_map());
1420 }
1421 JSArray* array = JSArray::cast(new_object);
1422 array->set_properties(Heap::empty_fixed_array());
1423 array->set_elements(elements);
1424 array->set_length(Smi::FromInt(elements_count));
1425 // Write in-object properties after the length of the array.
1426 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]);
1427 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]);
1428 return array;
1429}
1430
1431
lrn@chromium.org303ada72010-10-27 09:33:13 +00001432static MaybeObject* Runtime_RegExpInitializeObject(Arguments args) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00001433 AssertNoAllocation no_alloc;
1434 ASSERT(args.length() == 5);
1435 CONVERT_CHECKED(JSRegExp, regexp, args[0]);
1436 CONVERT_CHECKED(String, source, args[1]);
1437
1438 Object* global = args[2];
1439 if (!global->IsTrue()) global = Heap::false_value();
1440
1441 Object* ignoreCase = args[3];
1442 if (!ignoreCase->IsTrue()) ignoreCase = Heap::false_value();
1443
1444 Object* multiline = args[4];
1445 if (!multiline->IsTrue()) multiline = Heap::false_value();
1446
1447 Map* map = regexp->map();
1448 Object* constructor = map->constructor();
1449 if (constructor->IsJSFunction() &&
1450 JSFunction::cast(constructor)->initial_map() == map) {
1451 // If we still have the original map, set in-object properties directly.
1452 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source);
1453 // TODO(lrn): Consider skipping write barrier on booleans as well.
1454 // Both true and false should be in oldspace at all times.
1455 regexp->InObjectPropertyAtPut(JSRegExp::kGlobalFieldIndex, global);
1456 regexp->InObjectPropertyAtPut(JSRegExp::kIgnoreCaseFieldIndex, ignoreCase);
1457 regexp->InObjectPropertyAtPut(JSRegExp::kMultilineFieldIndex, multiline);
1458 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
1459 Smi::FromInt(0),
1460 SKIP_WRITE_BARRIER);
1461 return regexp;
1462 }
1463
lrn@chromium.org303ada72010-10-27 09:33:13 +00001464 // Map has changed, so use generic, but slower, method. Since these
1465 // properties were all added as DONT_DELETE they must be present and
1466 // normal so no failures can be expected.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001467 PropertyAttributes final =
1468 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
1469 PropertyAttributes writable =
1470 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001471 MaybeObject* result;
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001472 result = regexp->SetLocalPropertyIgnoreAttributes(Heap::source_symbol(),
1473 source,
1474 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001475 ASSERT(!result->IsFailure());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001476 result = regexp->SetLocalPropertyIgnoreAttributes(Heap::global_symbol(),
1477 global,
1478 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001479 ASSERT(!result->IsFailure());
1480 result =
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001481 regexp->SetLocalPropertyIgnoreAttributes(Heap::ignore_case_symbol(),
1482 ignoreCase,
1483 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001484 ASSERT(!result->IsFailure());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001485 result = regexp->SetLocalPropertyIgnoreAttributes(Heap::multiline_symbol(),
1486 multiline,
1487 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001488 ASSERT(!result->IsFailure());
1489 result =
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001490 regexp->SetLocalPropertyIgnoreAttributes(Heap::last_index_symbol(),
1491 Smi::FromInt(0),
1492 writable);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001493 ASSERT(!result->IsFailure());
1494 USE(result);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001495 return regexp;
1496}
1497
1498
lrn@chromium.org303ada72010-10-27 09:33:13 +00001499static MaybeObject* Runtime_FinishArrayPrototypeSetup(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001500 HandleScope scope;
1501 ASSERT(args.length() == 1);
1502 CONVERT_ARG_CHECKED(JSArray, prototype, 0);
1503 // This is necessary to enable fast checks for absence of elements
1504 // on Array.prototype and below.
1505 prototype->set_elements(Heap::empty_fixed_array());
1506 return Smi::FromInt(0);
1507}
1508
1509
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001510static Handle<JSFunction> InstallBuiltin(Handle<JSObject> holder,
1511 const char* name,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001512 Builtins::Name builtin_name) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001513 Handle<String> key = Factory::LookupAsciiSymbol(name);
1514 Handle<Code> code(Builtins::builtin(builtin_name));
1515 Handle<JSFunction> optimized = Factory::NewFunction(key,
1516 JS_OBJECT_TYPE,
1517 JSObject::kHeaderSize,
1518 code,
1519 false);
1520 optimized->shared()->DontAdaptArguments();
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001521 SetProperty(holder, key, optimized, NONE);
1522 return optimized;
1523}
1524
1525
lrn@chromium.org303ada72010-10-27 09:33:13 +00001526static MaybeObject* Runtime_SpecialArrayFunctions(Arguments args) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001527 HandleScope scope;
1528 ASSERT(args.length() == 1);
1529 CONVERT_ARG_CHECKED(JSObject, holder, 0);
1530
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001531 InstallBuiltin(holder, "pop", Builtins::ArrayPop);
1532 InstallBuiltin(holder, "push", Builtins::ArrayPush);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001533 InstallBuiltin(holder, "shift", Builtins::ArrayShift);
1534 InstallBuiltin(holder, "unshift", Builtins::ArrayUnshift);
1535 InstallBuiltin(holder, "slice", Builtins::ArraySlice);
1536 InstallBuiltin(holder, "splice", Builtins::ArraySplice);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001537 InstallBuiltin(holder, "concat", Builtins::ArrayConcat);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001538
1539 return *holder;
1540}
1541
1542
lrn@chromium.org303ada72010-10-27 09:33:13 +00001543static MaybeObject* Runtime_GetGlobalReceiver(Arguments args) {
ager@chromium.org357bf652010-04-12 11:30:10 +00001544 // Returns a real global receiver, not one of builtins object.
1545 Context* global_context = Top::context()->global()->global_context();
1546 return global_context->global()->global_receiver();
1547}
1548
1549
lrn@chromium.org303ada72010-10-27 09:33:13 +00001550static MaybeObject* Runtime_MaterializeRegExpLiteral(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001551 HandleScope scope;
1552 ASSERT(args.length() == 4);
1553 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
1554 int index = Smi::cast(args[1])->value();
1555 Handle<String> pattern = args.at<String>(2);
1556 Handle<String> flags = args.at<String>(3);
1557
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001558 // Get the RegExp function from the context in the literals array.
1559 // This is the RegExp function from the context in which the
1560 // function was created. We do not use the RegExp function from the
1561 // current global context because this might be the RegExp function
1562 // from another context which we should not have access to.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001563 Handle<JSFunction> constructor =
ager@chromium.org236ad962008-09-25 09:45:57 +00001564 Handle<JSFunction>(
1565 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001566 // Compute the regular expression literal.
1567 bool has_pending_exception;
1568 Handle<Object> regexp =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001569 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
1570 &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001571 if (has_pending_exception) {
1572 ASSERT(Top::has_pending_exception());
1573 return Failure::Exception();
1574 }
1575 literals->set(index, *regexp);
1576 return *regexp;
1577}
1578
1579
lrn@chromium.org303ada72010-10-27 09:33:13 +00001580static MaybeObject* Runtime_FunctionGetName(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001581 NoHandleAllocation ha;
1582 ASSERT(args.length() == 1);
1583
1584 CONVERT_CHECKED(JSFunction, f, args[0]);
1585 return f->shared()->name();
1586}
1587
1588
lrn@chromium.org303ada72010-10-27 09:33:13 +00001589static MaybeObject* Runtime_FunctionSetName(Arguments args) {
ager@chromium.org236ad962008-09-25 09:45:57 +00001590 NoHandleAllocation ha;
1591 ASSERT(args.length() == 2);
1592
1593 CONVERT_CHECKED(JSFunction, f, args[0]);
1594 CONVERT_CHECKED(String, name, args[1]);
1595 f->shared()->set_name(name);
1596 return Heap::undefined_value();
1597}
1598
1599
lrn@chromium.org303ada72010-10-27 09:33:13 +00001600static MaybeObject* Runtime_FunctionRemovePrototype(Arguments args) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001601 NoHandleAllocation ha;
1602 ASSERT(args.length() == 1);
1603
1604 CONVERT_CHECKED(JSFunction, f, args[0]);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001605 Object* obj;
1606 { MaybeObject* maybe_obj = f->RemovePrototype();
1607 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1608 }
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001609
1610 return Heap::undefined_value();
1611}
1612
1613
lrn@chromium.org303ada72010-10-27 09:33:13 +00001614static MaybeObject* Runtime_FunctionGetScript(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001615 HandleScope scope;
1616 ASSERT(args.length() == 1);
1617
1618 CONVERT_CHECKED(JSFunction, fun, args[0]);
1619 Handle<Object> script = Handle<Object>(fun->shared()->script());
1620 if (!script->IsScript()) return Heap::undefined_value();
1621
1622 return *GetScriptWrapper(Handle<Script>::cast(script));
1623}
1624
1625
lrn@chromium.org303ada72010-10-27 09:33:13 +00001626static MaybeObject* Runtime_FunctionGetSourceCode(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001627 NoHandleAllocation ha;
1628 ASSERT(args.length() == 1);
1629
1630 CONVERT_CHECKED(JSFunction, f, args[0]);
1631 return f->shared()->GetSourceCode();
1632}
1633
1634
lrn@chromium.org303ada72010-10-27 09:33:13 +00001635static MaybeObject* Runtime_FunctionGetScriptSourcePosition(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001636 NoHandleAllocation ha;
1637 ASSERT(args.length() == 1);
1638
1639 CONVERT_CHECKED(JSFunction, fun, args[0]);
1640 int pos = fun->shared()->start_position();
1641 return Smi::FromInt(pos);
1642}
1643
1644
lrn@chromium.org303ada72010-10-27 09:33:13 +00001645static MaybeObject* Runtime_FunctionGetPositionForOffset(Arguments args) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001646 ASSERT(args.length() == 2);
1647
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001648 CONVERT_CHECKED(Code, code, args[0]);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001649 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
1650
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001651 RUNTIME_ASSERT(0 <= offset && offset < code->Size());
1652
1653 Address pc = code->address() + offset;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001654 return Smi::FromInt(code->SourcePosition(pc));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001655}
1656
1657
1658
lrn@chromium.org303ada72010-10-27 09:33:13 +00001659static MaybeObject* Runtime_FunctionSetInstanceClassName(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001660 NoHandleAllocation ha;
1661 ASSERT(args.length() == 2);
1662
1663 CONVERT_CHECKED(JSFunction, fun, args[0]);
1664 CONVERT_CHECKED(String, name, args[1]);
1665 fun->SetInstanceClassName(name);
1666 return Heap::undefined_value();
1667}
1668
1669
lrn@chromium.org303ada72010-10-27 09:33:13 +00001670static MaybeObject* Runtime_FunctionSetLength(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001671 NoHandleAllocation ha;
1672 ASSERT(args.length() == 2);
1673
1674 CONVERT_CHECKED(JSFunction, fun, args[0]);
1675 CONVERT_CHECKED(Smi, length, args[1]);
1676 fun->shared()->set_length(length->value());
1677 return length;
1678}
1679
1680
lrn@chromium.org303ada72010-10-27 09:33:13 +00001681static MaybeObject* Runtime_FunctionSetPrototype(Arguments args) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001682 NoHandleAllocation ha;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001683 ASSERT(args.length() == 2);
1684
1685 CONVERT_CHECKED(JSFunction, fun, args[0]);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001686 ASSERT(fun->should_have_prototype());
lrn@chromium.org303ada72010-10-27 09:33:13 +00001687 Object* obj;
1688 { MaybeObject* maybe_obj =
1689 Accessors::FunctionSetPrototype(fun, args[1], NULL);
1690 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1691 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001692 return args[0]; // return TOS
1693}
1694
1695
lrn@chromium.org303ada72010-10-27 09:33:13 +00001696static MaybeObject* Runtime_FunctionIsAPIFunction(Arguments args) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001697 NoHandleAllocation ha;
1698 ASSERT(args.length() == 1);
1699
1700 CONVERT_CHECKED(JSFunction, f, args[0]);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001701 return f->shared()->IsApiFunction() ? Heap::true_value()
1702 : Heap::false_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001703}
1704
lrn@chromium.org303ada72010-10-27 09:33:13 +00001705static MaybeObject* Runtime_FunctionIsBuiltin(Arguments args) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001706 NoHandleAllocation ha;
1707 ASSERT(args.length() == 1);
1708
1709 CONVERT_CHECKED(JSFunction, f, args[0]);
1710 return f->IsBuiltin() ? Heap::true_value() : Heap::false_value();
1711}
1712
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001713
lrn@chromium.org303ada72010-10-27 09:33:13 +00001714static MaybeObject* Runtime_SetCode(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001715 HandleScope scope;
1716 ASSERT(args.length() == 2);
1717
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001718 CONVERT_ARG_CHECKED(JSFunction, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001719 Handle<Object> code = args.at<Object>(1);
1720
1721 Handle<Context> context(target->context());
1722
1723 if (!code->IsNull()) {
1724 RUNTIME_ASSERT(code->IsJSFunction());
1725 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001726 Handle<SharedFunctionInfo> shared(fun->shared());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001727
1728 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001729 return Failure::Exception();
1730 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001731 // Since we don't store the source for this we should never
1732 // optimize this.
1733 shared->code()->set_optimizable(false);
1734
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001735 // Set the code, scope info, formal parameter count,
1736 // and the length of the target function.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00001737 target->shared()->set_code(shared->code());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001738 target->ReplaceCode(shared->code());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001739 target->shared()->set_scope_info(shared->scope_info());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001740 target->shared()->set_length(shared->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001741 target->shared()->set_formal_parameter_count(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001742 shared->formal_parameter_count());
ager@chromium.org7c537e22008-10-16 08:43:32 +00001743 // Set the source code of the target function to undefined.
1744 // SetCode is only used for built-in constructors like String,
1745 // Array, and Object, and some web code
1746 // doesn't like seeing source code for constructors.
1747 target->shared()->set_script(Heap::undefined_value());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001748 target->shared()->code()->set_optimizable(false);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001749 // Clear the optimization hints related to the compiled code as these are no
1750 // longer valid when the code is overwritten.
1751 target->shared()->ClearThisPropertyAssignmentsInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001752 context = Handle<Context>(fun->context());
1753
1754 // Make sure we get a fresh copy of the literal vector to avoid
1755 // cross context contamination.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001756 int number_of_literals = fun->NumberOfLiterals();
1757 Handle<FixedArray> literals =
1758 Factory::NewFixedArray(number_of_literals, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001759 if (number_of_literals > 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001760 // Insert the object, regexp and array functions in the literals
1761 // array prefix. These are the functions that will be used when
1762 // creating object, regexp and array literals.
ager@chromium.org236ad962008-09-25 09:45:57 +00001763 literals->set(JSFunction::kLiteralGlobalContextIndex,
1764 context->global_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001765 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001766 // It's okay to skip the write barrier here because the literals
1767 // are guaranteed to be in old space.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001768 target->set_literals(*literals, SKIP_WRITE_BARRIER);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001769 target->set_next_function_link(Heap::undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001770 }
1771
1772 target->set_context(*context);
1773 return *target;
1774}
1775
1776
lrn@chromium.org303ada72010-10-27 09:33:13 +00001777static MaybeObject* Runtime_SetExpectedNumberOfProperties(Arguments args) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001778 HandleScope scope;
1779 ASSERT(args.length() == 2);
1780 CONVERT_ARG_CHECKED(JSFunction, function, 0);
1781 CONVERT_SMI_CHECKED(num, args[1]);
1782 RUNTIME_ASSERT(num >= 0);
1783 SetExpectedNofProperties(function, num);
1784 return Heap::undefined_value();
1785}
1786
1787
lrn@chromium.org303ada72010-10-27 09:33:13 +00001788MUST_USE_RESULT static MaybeObject* CharFromCode(Object* char_code) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001789 uint32_t code;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001790 if (char_code->ToArrayIndex(&code)) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001791 if (code <= 0xffff) {
1792 return Heap::LookupSingleCharacterStringFromCode(code);
1793 }
1794 }
1795 return Heap::empty_string();
1796}
1797
1798
lrn@chromium.org303ada72010-10-27 09:33:13 +00001799static MaybeObject* Runtime_StringCharCodeAt(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001800 NoHandleAllocation ha;
1801 ASSERT(args.length() == 2);
1802
1803 CONVERT_CHECKED(String, subject, args[0]);
1804 Object* index = args[1];
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001805 RUNTIME_ASSERT(index->IsNumber());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001806
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001807 uint32_t i = 0;
1808 if (index->IsSmi()) {
1809 int value = Smi::cast(index)->value();
1810 if (value < 0) return Heap::nan_value();
1811 i = value;
1812 } else {
1813 ASSERT(index->IsHeapNumber());
1814 double value = HeapNumber::cast(index)->value();
1815 i = static_cast<uint32_t>(DoubleToInteger(value));
kasperl@chromium.org74e4e5e2010-01-25 10:15:52 +00001816 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001817
1818 // Flatten the string. If someone wants to get a char at an index
1819 // in a cons string, it is likely that more indices will be
1820 // accessed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001821 Object* flat;
1822 { MaybeObject* maybe_flat = subject->TryFlatten();
1823 if (!maybe_flat->ToObject(&flat)) return maybe_flat;
1824 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001825 subject = String::cast(flat);
1826
1827 if (i >= static_cast<uint32_t>(subject->length())) {
1828 return Heap::nan_value();
1829 }
1830
1831 return Smi::FromInt(subject->Get(i));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001832}
1833
1834
lrn@chromium.org303ada72010-10-27 09:33:13 +00001835static MaybeObject* Runtime_CharFromCode(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001836 NoHandleAllocation ha;
1837 ASSERT(args.length() == 1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001838 return CharFromCode(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001839}
1840
lrn@chromium.org25156de2010-04-06 13:10:27 +00001841
1842class FixedArrayBuilder {
1843 public:
1844 explicit FixedArrayBuilder(int initial_capacity)
1845 : array_(Factory::NewFixedArrayWithHoles(initial_capacity)),
1846 length_(0) {
1847 // Require a non-zero initial size. Ensures that doubling the size to
1848 // extend the array will work.
1849 ASSERT(initial_capacity > 0);
1850 }
1851
1852 explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
1853 : array_(backing_store),
1854 length_(0) {
1855 // Require a non-zero initial size. Ensures that doubling the size to
1856 // extend the array will work.
1857 ASSERT(backing_store->length() > 0);
1858 }
1859
1860 bool HasCapacity(int elements) {
1861 int length = array_->length();
1862 int required_length = length_ + elements;
1863 return (length >= required_length);
1864 }
1865
1866 void EnsureCapacity(int elements) {
1867 int length = array_->length();
1868 int required_length = length_ + elements;
1869 if (length < required_length) {
1870 int new_length = length;
1871 do {
1872 new_length *= 2;
1873 } while (new_length < required_length);
1874 Handle<FixedArray> extended_array =
1875 Factory::NewFixedArrayWithHoles(new_length);
1876 array_->CopyTo(0, *extended_array, 0, length_);
1877 array_ = extended_array;
1878 }
1879 }
1880
1881 void Add(Object* value) {
1882 ASSERT(length_ < capacity());
1883 array_->set(length_, value);
1884 length_++;
1885 }
1886
1887 void Add(Smi* value) {
1888 ASSERT(length_ < capacity());
1889 array_->set(length_, value);
1890 length_++;
1891 }
1892
1893 Handle<FixedArray> array() {
1894 return array_;
1895 }
1896
1897 int length() {
1898 return length_;
1899 }
1900
1901 int capacity() {
1902 return array_->length();
1903 }
1904
1905 Handle<JSArray> ToJSArray() {
1906 Handle<JSArray> result_array = Factory::NewJSArrayWithElements(array_);
1907 result_array->set_length(Smi::FromInt(length_));
1908 return result_array;
1909 }
1910
1911 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
1912 target_array->set_elements(*array_);
1913 target_array->set_length(Smi::FromInt(length_));
1914 return target_array;
1915 }
1916
1917 private:
1918 Handle<FixedArray> array_;
1919 int length_;
1920};
1921
1922
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001923// Forward declarations.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001924const int kStringBuilderConcatHelperLengthBits = 11;
1925const int kStringBuilderConcatHelperPositionBits = 19;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001926
1927template <typename schar>
1928static inline void StringBuilderConcatHelper(String*,
1929 schar*,
1930 FixedArray*,
1931 int);
1932
lrn@chromium.org25156de2010-04-06 13:10:27 +00001933typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
1934 StringBuilderSubstringLength;
1935typedef BitField<int,
1936 kStringBuilderConcatHelperLengthBits,
1937 kStringBuilderConcatHelperPositionBits>
1938 StringBuilderSubstringPosition;
1939
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001940
1941class ReplacementStringBuilder {
1942 public:
1943 ReplacementStringBuilder(Handle<String> subject, int estimated_part_count)
lrn@chromium.org25156de2010-04-06 13:10:27 +00001944 : array_builder_(estimated_part_count),
1945 subject_(subject),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001946 character_count_(0),
ager@chromium.org5ec48922009-05-05 07:25:34 +00001947 is_ascii_(subject->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001948 // Require a non-zero initial size. Ensures that doubling the size to
1949 // extend the array will work.
1950 ASSERT(estimated_part_count > 0);
1951 }
1952
lrn@chromium.org25156de2010-04-06 13:10:27 +00001953 static inline void AddSubjectSlice(FixedArrayBuilder* builder,
1954 int from,
1955 int to) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001956 ASSERT(from >= 0);
1957 int length = to - from;
1958 ASSERT(length > 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001959 if (StringBuilderSubstringLength::is_valid(length) &&
1960 StringBuilderSubstringPosition::is_valid(from)) {
1961 int encoded_slice = StringBuilderSubstringLength::encode(length) |
1962 StringBuilderSubstringPosition::encode(from);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001963 builder->Add(Smi::FromInt(encoded_slice));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001964 } else {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001965 // Otherwise encode as two smis.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001966 builder->Add(Smi::FromInt(-length));
1967 builder->Add(Smi::FromInt(from));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001968 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00001969 }
1970
1971
1972 void EnsureCapacity(int elements) {
1973 array_builder_.EnsureCapacity(elements);
1974 }
1975
1976
1977 void AddSubjectSlice(int from, int to) {
1978 AddSubjectSlice(&array_builder_, from, to);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001979 IncrementCharacterCount(to - from);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001980 }
1981
1982
1983 void AddString(Handle<String> string) {
1984 int length = string->length();
1985 ASSERT(length > 0);
1986 AddElement(*string);
ager@chromium.org5ec48922009-05-05 07:25:34 +00001987 if (!string->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001988 is_ascii_ = false;
1989 }
1990 IncrementCharacterCount(length);
1991 }
1992
1993
1994 Handle<String> ToString() {
lrn@chromium.org25156de2010-04-06 13:10:27 +00001995 if (array_builder_.length() == 0) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001996 return Factory::empty_string();
1997 }
1998
1999 Handle<String> joined_string;
2000 if (is_ascii_) {
2001 joined_string = NewRawAsciiString(character_count_);
2002 AssertNoAllocation no_alloc;
2003 SeqAsciiString* seq = SeqAsciiString::cast(*joined_string);
2004 char* char_buffer = seq->GetChars();
2005 StringBuilderConcatHelper(*subject_,
2006 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002007 *array_builder_.array(),
2008 array_builder_.length());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002009 } else {
2010 // Non-ASCII.
2011 joined_string = NewRawTwoByteString(character_count_);
2012 AssertNoAllocation no_alloc;
2013 SeqTwoByteString* seq = SeqTwoByteString::cast(*joined_string);
2014 uc16* char_buffer = seq->GetChars();
2015 StringBuilderConcatHelper(*subject_,
2016 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002017 *array_builder_.array(),
2018 array_builder_.length());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002019 }
2020 return joined_string;
2021 }
2022
2023
2024 void IncrementCharacterCount(int by) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002025 if (character_count_ > String::kMaxLength - by) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002026 V8::FatalProcessOutOfMemory("String.replace result too large.");
2027 }
2028 character_count_ += by;
2029 }
2030
lrn@chromium.org25156de2010-04-06 13:10:27 +00002031 Handle<JSArray> GetParts() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002032 return array_builder_.ToJSArray();
lrn@chromium.org25156de2010-04-06 13:10:27 +00002033 }
kmillikin@chromium.orgd9825192010-03-30 08:36:16 +00002034
lrn@chromium.org25156de2010-04-06 13:10:27 +00002035 private:
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002036 Handle<String> NewRawAsciiString(int size) {
2037 CALL_HEAP_FUNCTION(Heap::AllocateRawAsciiString(size), String);
2038 }
2039
2040
2041 Handle<String> NewRawTwoByteString(int size) {
2042 CALL_HEAP_FUNCTION(Heap::AllocateRawTwoByteString(size), String);
2043 }
2044
2045
2046 void AddElement(Object* element) {
2047 ASSERT(element->IsSmi() || element->IsString());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002048 ASSERT(array_builder_.capacity() > array_builder_.length());
2049 array_builder_.Add(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002050 }
2051
lrn@chromium.org25156de2010-04-06 13:10:27 +00002052 FixedArrayBuilder array_builder_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002053 Handle<String> subject_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002054 int character_count_;
2055 bool is_ascii_;
2056};
2057
2058
2059class CompiledReplacement {
2060 public:
2061 CompiledReplacement()
2062 : parts_(1), replacement_substrings_(0) {}
2063
2064 void Compile(Handle<String> replacement,
2065 int capture_count,
2066 int subject_length);
2067
2068 void Apply(ReplacementStringBuilder* builder,
2069 int match_from,
2070 int match_to,
2071 Handle<JSArray> last_match_info);
2072
2073 // Number of distinct parts of the replacement pattern.
2074 int parts() {
2075 return parts_.length();
2076 }
2077 private:
2078 enum PartType {
2079 SUBJECT_PREFIX = 1,
2080 SUBJECT_SUFFIX,
2081 SUBJECT_CAPTURE,
2082 REPLACEMENT_SUBSTRING,
2083 REPLACEMENT_STRING,
2084
2085 NUMBER_OF_PART_TYPES
2086 };
2087
2088 struct ReplacementPart {
2089 static inline ReplacementPart SubjectMatch() {
2090 return ReplacementPart(SUBJECT_CAPTURE, 0);
2091 }
2092 static inline ReplacementPart SubjectCapture(int capture_index) {
2093 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
2094 }
2095 static inline ReplacementPart SubjectPrefix() {
2096 return ReplacementPart(SUBJECT_PREFIX, 0);
2097 }
2098 static inline ReplacementPart SubjectSuffix(int subject_length) {
2099 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
2100 }
2101 static inline ReplacementPart ReplacementString() {
2102 return ReplacementPart(REPLACEMENT_STRING, 0);
2103 }
2104 static inline ReplacementPart ReplacementSubString(int from, int to) {
2105 ASSERT(from >= 0);
2106 ASSERT(to > from);
2107 return ReplacementPart(-from, to);
2108 }
2109
2110 // If tag <= 0 then it is the negation of a start index of a substring of
2111 // the replacement pattern, otherwise it's a value from PartType.
2112 ReplacementPart(int tag, int data)
2113 : tag(tag), data(data) {
2114 // Must be non-positive or a PartType value.
2115 ASSERT(tag < NUMBER_OF_PART_TYPES);
2116 }
2117 // Either a value of PartType or a non-positive number that is
2118 // the negation of an index into the replacement string.
2119 int tag;
2120 // The data value's interpretation depends on the value of tag:
2121 // tag == SUBJECT_PREFIX ||
2122 // tag == SUBJECT_SUFFIX: data is unused.
2123 // tag == SUBJECT_CAPTURE: data is the number of the capture.
2124 // tag == REPLACEMENT_SUBSTRING ||
2125 // tag == REPLACEMENT_STRING: data is index into array of substrings
2126 // of the replacement string.
2127 // tag <= 0: Temporary representation of the substring of the replacement
2128 // string ranging over -tag .. data.
2129 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
2130 // substring objects.
2131 int data;
2132 };
2133
2134 template<typename Char>
2135 static void ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
2136 Vector<Char> characters,
2137 int capture_count,
2138 int subject_length) {
2139 int length = characters.length();
2140 int last = 0;
2141 for (int i = 0; i < length; i++) {
2142 Char c = characters[i];
2143 if (c == '$') {
2144 int next_index = i + 1;
2145 if (next_index == length) { // No next character!
2146 break;
2147 }
2148 Char c2 = characters[next_index];
2149 switch (c2) {
2150 case '$':
2151 if (i > last) {
2152 // There is a substring before. Include the first "$".
2153 parts->Add(ReplacementPart::ReplacementSubString(last, next_index));
2154 last = next_index + 1; // Continue after the second "$".
2155 } else {
2156 // Let the next substring start with the second "$".
2157 last = next_index;
2158 }
2159 i = next_index;
2160 break;
2161 case '`':
2162 if (i > last) {
2163 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2164 }
2165 parts->Add(ReplacementPart::SubjectPrefix());
2166 i = next_index;
2167 last = i + 1;
2168 break;
2169 case '\'':
2170 if (i > last) {
2171 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2172 }
2173 parts->Add(ReplacementPart::SubjectSuffix(subject_length));
2174 i = next_index;
2175 last = i + 1;
2176 break;
2177 case '&':
2178 if (i > last) {
2179 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2180 }
2181 parts->Add(ReplacementPart::SubjectMatch());
2182 i = next_index;
2183 last = i + 1;
2184 break;
2185 case '0':
2186 case '1':
2187 case '2':
2188 case '3':
2189 case '4':
2190 case '5':
2191 case '6':
2192 case '7':
2193 case '8':
2194 case '9': {
2195 int capture_ref = c2 - '0';
2196 if (capture_ref > capture_count) {
2197 i = next_index;
2198 continue;
2199 }
2200 int second_digit_index = next_index + 1;
2201 if (second_digit_index < length) {
2202 // Peek ahead to see if we have two digits.
2203 Char c3 = characters[second_digit_index];
2204 if ('0' <= c3 && c3 <= '9') { // Double digits.
2205 int double_digit_ref = capture_ref * 10 + c3 - '0';
2206 if (double_digit_ref <= capture_count) {
2207 next_index = second_digit_index;
2208 capture_ref = double_digit_ref;
2209 }
2210 }
2211 }
2212 if (capture_ref > 0) {
2213 if (i > last) {
2214 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2215 }
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002216 ASSERT(capture_ref <= capture_count);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002217 parts->Add(ReplacementPart::SubjectCapture(capture_ref));
2218 last = next_index + 1;
2219 }
2220 i = next_index;
2221 break;
2222 }
2223 default:
2224 i = next_index;
2225 break;
2226 }
2227 }
2228 }
2229 if (length > last) {
2230 if (last == 0) {
2231 parts->Add(ReplacementPart::ReplacementString());
2232 } else {
2233 parts->Add(ReplacementPart::ReplacementSubString(last, length));
2234 }
2235 }
2236 }
2237
2238 ZoneList<ReplacementPart> parts_;
2239 ZoneList<Handle<String> > replacement_substrings_;
2240};
2241
2242
2243void CompiledReplacement::Compile(Handle<String> replacement,
2244 int capture_count,
2245 int subject_length) {
2246 ASSERT(replacement->IsFlat());
ager@chromium.org5ec48922009-05-05 07:25:34 +00002247 if (replacement->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002248 AssertNoAllocation no_alloc;
2249 ParseReplacementPattern(&parts_,
2250 replacement->ToAsciiVector(),
2251 capture_count,
2252 subject_length);
2253 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00002254 ASSERT(replacement->IsTwoByteRepresentation());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002255 AssertNoAllocation no_alloc;
2256
2257 ParseReplacementPattern(&parts_,
2258 replacement->ToUC16Vector(),
2259 capture_count,
2260 subject_length);
2261 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002262 // Find substrings of replacement string and create them as String objects.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002263 int substring_index = 0;
2264 for (int i = 0, n = parts_.length(); i < n; i++) {
2265 int tag = parts_[i].tag;
2266 if (tag <= 0) { // A replacement string slice.
2267 int from = -tag;
2268 int to = parts_[i].data;
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002269 replacement_substrings_.Add(Factory::NewSubString(replacement, from, to));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002270 parts_[i].tag = REPLACEMENT_SUBSTRING;
2271 parts_[i].data = substring_index;
2272 substring_index++;
2273 } else if (tag == REPLACEMENT_STRING) {
2274 replacement_substrings_.Add(replacement);
2275 parts_[i].data = substring_index;
2276 substring_index++;
2277 }
2278 }
2279}
2280
2281
2282void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
2283 int match_from,
2284 int match_to,
2285 Handle<JSArray> last_match_info) {
2286 for (int i = 0, n = parts_.length(); i < n; i++) {
2287 ReplacementPart part = parts_[i];
2288 switch (part.tag) {
2289 case SUBJECT_PREFIX:
2290 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
2291 break;
2292 case SUBJECT_SUFFIX: {
2293 int subject_length = part.data;
2294 if (match_to < subject_length) {
2295 builder->AddSubjectSlice(match_to, subject_length);
2296 }
2297 break;
2298 }
2299 case SUBJECT_CAPTURE: {
2300 int capture = part.data;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002301 FixedArray* match_info = FixedArray::cast(last_match_info->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002302 int from = RegExpImpl::GetCapture(match_info, capture * 2);
2303 int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1);
2304 if (from >= 0 && to > from) {
2305 builder->AddSubjectSlice(from, to);
2306 }
2307 break;
2308 }
2309 case REPLACEMENT_SUBSTRING:
2310 case REPLACEMENT_STRING:
2311 builder->AddString(replacement_substrings_[part.data]);
2312 break;
2313 default:
2314 UNREACHABLE();
2315 }
2316 }
2317}
2318
2319
2320
lrn@chromium.org303ada72010-10-27 09:33:13 +00002321MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
2322 String* subject,
2323 JSRegExp* regexp,
2324 String* replacement,
2325 JSArray* last_match_info) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002326 ASSERT(subject->IsFlat());
2327 ASSERT(replacement->IsFlat());
2328
2329 HandleScope handles;
2330
2331 int length = subject->length();
2332 Handle<String> subject_handle(subject);
2333 Handle<JSRegExp> regexp_handle(regexp);
2334 Handle<String> replacement_handle(replacement);
2335 Handle<JSArray> last_match_info_handle(last_match_info);
2336 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2337 subject_handle,
2338 0,
2339 last_match_info_handle);
2340 if (match.is_null()) {
2341 return Failure::Exception();
2342 }
2343 if (match->IsNull()) {
2344 return *subject_handle;
2345 }
2346
2347 int capture_count = regexp_handle->CaptureCount();
2348
2349 // CompiledReplacement uses zone allocation.
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00002350 CompilationZoneScope zone(DELETE_ON_EXIT);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002351 CompiledReplacement compiled_replacement;
2352 compiled_replacement.Compile(replacement_handle,
2353 capture_count,
2354 length);
2355
2356 bool is_global = regexp_handle->GetFlags().is_global();
2357
2358 // Guessing the number of parts that the final result string is built
2359 // from. Global regexps can match any number of times, so we guess
2360 // conservatively.
2361 int expected_parts =
2362 (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1;
2363 ReplacementStringBuilder builder(subject_handle, expected_parts);
2364
2365 // Index of end of last match.
2366 int prev = 0;
2367
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002368 // Number of parts added by compiled replacement plus preceeding
2369 // string and possibly suffix after last match. It is possible for
2370 // all components to use two elements when encoded as two smis.
2371 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002372 bool matched = true;
2373 do {
2374 ASSERT(last_match_info_handle->HasFastElements());
2375 // Increase the capacity of the builder before entering local handle-scope,
2376 // so its internal buffer can safely allocate a new handle if it grows.
2377 builder.EnsureCapacity(parts_added_per_loop);
2378
2379 HandleScope loop_scope;
2380 int start, end;
2381 {
2382 AssertNoAllocation match_info_array_is_not_in_a_handle;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002383 FixedArray* match_info_array =
2384 FixedArray::cast(last_match_info_handle->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002385
2386 ASSERT_EQ(capture_count * 2 + 2,
2387 RegExpImpl::GetLastCaptureCount(match_info_array));
2388 start = RegExpImpl::GetCapture(match_info_array, 0);
2389 end = RegExpImpl::GetCapture(match_info_array, 1);
2390 }
2391
2392 if (prev < start) {
2393 builder.AddSubjectSlice(prev, start);
2394 }
2395 compiled_replacement.Apply(&builder,
2396 start,
2397 end,
2398 last_match_info_handle);
2399 prev = end;
2400
2401 // Only continue checking for global regexps.
2402 if (!is_global) break;
2403
2404 // Continue from where the match ended, unless it was an empty match.
2405 int next = end;
2406 if (start == end) {
2407 next = end + 1;
2408 if (next > length) break;
2409 }
2410
2411 match = RegExpImpl::Exec(regexp_handle,
2412 subject_handle,
2413 next,
2414 last_match_info_handle);
2415 if (match.is_null()) {
2416 return Failure::Exception();
2417 }
2418 matched = !match->IsNull();
2419 } while (matched);
2420
2421 if (prev < length) {
2422 builder.AddSubjectSlice(prev, length);
2423 }
2424
2425 return *(builder.ToString());
2426}
2427
2428
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002429template <typename ResultSeqString>
lrn@chromium.org303ada72010-10-27 09:33:13 +00002430MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
2431 String* subject,
2432 JSRegExp* regexp,
2433 JSArray* last_match_info) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002434 ASSERT(subject->IsFlat());
2435
2436 HandleScope handles;
2437
2438 Handle<String> subject_handle(subject);
2439 Handle<JSRegExp> regexp_handle(regexp);
2440 Handle<JSArray> last_match_info_handle(last_match_info);
2441 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2442 subject_handle,
2443 0,
2444 last_match_info_handle);
2445 if (match.is_null()) return Failure::Exception();
2446 if (match->IsNull()) return *subject_handle;
2447
2448 ASSERT(last_match_info_handle->HasFastElements());
2449
2450 HandleScope loop_scope;
2451 int start, end;
2452 {
2453 AssertNoAllocation match_info_array_is_not_in_a_handle;
2454 FixedArray* match_info_array =
2455 FixedArray::cast(last_match_info_handle->elements());
2456
2457 start = RegExpImpl::GetCapture(match_info_array, 0);
2458 end = RegExpImpl::GetCapture(match_info_array, 1);
2459 }
2460
2461 int length = subject->length();
2462 int new_length = length - (end - start);
2463 if (new_length == 0) {
2464 return Heap::empty_string();
2465 }
2466 Handle<ResultSeqString> answer;
2467 if (ResultSeqString::kHasAsciiEncoding) {
2468 answer =
2469 Handle<ResultSeqString>::cast(Factory::NewRawAsciiString(new_length));
2470 } else {
2471 answer =
2472 Handle<ResultSeqString>::cast(Factory::NewRawTwoByteString(new_length));
2473 }
2474
2475 // If the regexp isn't global, only match once.
2476 if (!regexp_handle->GetFlags().is_global()) {
2477 if (start > 0) {
2478 String::WriteToFlat(*subject_handle,
2479 answer->GetChars(),
2480 0,
2481 start);
2482 }
2483 if (end < length) {
2484 String::WriteToFlat(*subject_handle,
2485 answer->GetChars() + start,
2486 end,
2487 length);
2488 }
2489 return *answer;
2490 }
2491
2492 int prev = 0; // Index of end of last match.
2493 int next = 0; // Start of next search (prev unless last match was empty).
2494 int position = 0;
2495
2496 do {
2497 if (prev < start) {
2498 // Add substring subject[prev;start] to answer string.
2499 String::WriteToFlat(*subject_handle,
2500 answer->GetChars() + position,
2501 prev,
2502 start);
2503 position += start - prev;
2504 }
2505 prev = end;
2506 next = end;
2507 // Continue from where the match ended, unless it was an empty match.
2508 if (start == end) {
2509 next++;
2510 if (next > length) break;
2511 }
2512 match = RegExpImpl::Exec(regexp_handle,
2513 subject_handle,
2514 next,
2515 last_match_info_handle);
2516 if (match.is_null()) return Failure::Exception();
2517 if (match->IsNull()) break;
2518
2519 ASSERT(last_match_info_handle->HasFastElements());
2520 HandleScope loop_scope;
2521 {
2522 AssertNoAllocation match_info_array_is_not_in_a_handle;
2523 FixedArray* match_info_array =
2524 FixedArray::cast(last_match_info_handle->elements());
2525 start = RegExpImpl::GetCapture(match_info_array, 0);
2526 end = RegExpImpl::GetCapture(match_info_array, 1);
2527 }
2528 } while (true);
2529
2530 if (prev < length) {
2531 // Add substring subject[prev;length] to answer string.
2532 String::WriteToFlat(*subject_handle,
2533 answer->GetChars() + position,
2534 prev,
2535 length);
2536 position += length - prev;
2537 }
2538
2539 if (position == 0) {
2540 return Heap::empty_string();
2541 }
2542
2543 // Shorten string and fill
2544 int string_size = ResultSeqString::SizeFor(position);
2545 int allocated_string_size = ResultSeqString::SizeFor(new_length);
2546 int delta = allocated_string_size - string_size;
2547
2548 answer->set_length(position);
2549 if (delta == 0) return *answer;
2550
2551 Address end_of_string = answer->address() + string_size;
2552 Heap::CreateFillerObjectAt(end_of_string, delta);
2553
2554 return *answer;
2555}
2556
2557
lrn@chromium.org303ada72010-10-27 09:33:13 +00002558static MaybeObject* Runtime_StringReplaceRegExpWithString(Arguments args) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002559 ASSERT(args.length() == 4);
2560
2561 CONVERT_CHECKED(String, subject, args[0]);
2562 if (!subject->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002563 Object* flat_subject;
2564 { MaybeObject* maybe_flat_subject = subject->TryFlatten();
2565 if (!maybe_flat_subject->ToObject(&flat_subject)) {
2566 return maybe_flat_subject;
2567 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002568 }
2569 subject = String::cast(flat_subject);
2570 }
2571
2572 CONVERT_CHECKED(String, replacement, args[2]);
2573 if (!replacement->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002574 Object* flat_replacement;
2575 { MaybeObject* maybe_flat_replacement = replacement->TryFlatten();
2576 if (!maybe_flat_replacement->ToObject(&flat_replacement)) {
2577 return maybe_flat_replacement;
2578 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002579 }
2580 replacement = String::cast(flat_replacement);
2581 }
2582
2583 CONVERT_CHECKED(JSRegExp, regexp, args[1]);
2584 CONVERT_CHECKED(JSArray, last_match_info, args[3]);
2585
2586 ASSERT(last_match_info->HasFastElements());
2587
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002588 if (replacement->length() == 0) {
2589 if (subject->HasOnlyAsciiChars()) {
2590 return StringReplaceRegExpWithEmptyString<SeqAsciiString>(
2591 subject, regexp, last_match_info);
2592 } else {
2593 return StringReplaceRegExpWithEmptyString<SeqTwoByteString>(
2594 subject, regexp, last_match_info);
2595 }
2596 }
2597
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002598 return StringReplaceRegExpWithString(subject,
2599 regexp,
2600 replacement,
2601 last_match_info);
2602}
2603
2604
ager@chromium.org7c537e22008-10-16 08:43:32 +00002605// Perform string match of pattern on subject, starting at start index.
2606// Caller must ensure that 0 <= start_index <= sub->length(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002607// and should check that pat->length() + start_index <= sub->length().
ager@chromium.org7c537e22008-10-16 08:43:32 +00002608int Runtime::StringMatch(Handle<String> sub,
2609 Handle<String> pat,
2610 int start_index) {
2611 ASSERT(0 <= start_index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002612 ASSERT(start_index <= sub->length());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002613
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00002614 int pattern_length = pat->length();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002615 if (pattern_length == 0) return start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002616
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002617 int subject_length = sub->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00002618 if (start_index + pattern_length > subject_length) return -1;
2619
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002620 if (!sub->IsFlat()) FlattenString(sub);
2621 if (!pat->IsFlat()) FlattenString(pat);
ager@chromium.org236ad962008-09-25 09:45:57 +00002622
ager@chromium.org7c537e22008-10-16 08:43:32 +00002623 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002624 // Extract flattened substrings of cons strings before determining asciiness.
2625 String* seq_sub = *sub;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002626 if (seq_sub->IsConsString()) seq_sub = ConsString::cast(seq_sub)->first();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002627 String* seq_pat = *pat;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002628 if (seq_pat->IsConsString()) seq_pat = ConsString::cast(seq_pat)->first();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002629
ager@chromium.org7c537e22008-10-16 08:43:32 +00002630 // dispatch on type of strings
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002631 if (seq_pat->IsAsciiRepresentation()) {
2632 Vector<const char> pat_vector = seq_pat->ToAsciiVector();
2633 if (seq_sub->IsAsciiRepresentation()) {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002634 return SearchString(seq_sub->ToAsciiVector(), pat_vector, start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00002635 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002636 return SearchString(seq_sub->ToUC16Vector(), pat_vector, start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00002637 }
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002638 Vector<const uc16> pat_vector = seq_pat->ToUC16Vector();
2639 if (seq_sub->IsAsciiRepresentation()) {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002640 return SearchString(seq_sub->ToAsciiVector(), pat_vector, start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002641 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002642 return SearchString(seq_sub->ToUC16Vector(), pat_vector, start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002643}
2644
2645
lrn@chromium.org303ada72010-10-27 09:33:13 +00002646static MaybeObject* Runtime_StringIndexOf(Arguments args) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00002647 HandleScope scope; // create a new handle scope
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002648 ASSERT(args.length() == 3);
2649
ager@chromium.org7c537e22008-10-16 08:43:32 +00002650 CONVERT_ARG_CHECKED(String, sub, 0);
2651 CONVERT_ARG_CHECKED(String, pat, 1);
2652
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002653 Object* index = args[2];
2654 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002655 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002656
ager@chromium.org870a0b62008-11-04 11:43:05 +00002657 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
ager@chromium.org7c537e22008-10-16 08:43:32 +00002658 int position = Runtime::StringMatch(sub, pat, start_index);
2659 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002660}
2661
2662
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002663template <typename schar, typename pchar>
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002664static int StringMatchBackwards(Vector<const schar> subject,
2665 Vector<const pchar> pattern,
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002666 int idx) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002667 int pattern_length = pattern.length();
2668 ASSERT(pattern_length >= 1);
2669 ASSERT(idx + pattern_length <= subject.length());
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002670
2671 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002672 for (int i = 0; i < pattern_length; i++) {
2673 uc16 c = pattern[i];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002674 if (c > String::kMaxAsciiCharCode) {
2675 return -1;
2676 }
2677 }
2678 }
2679
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002680 pchar pattern_first_char = pattern[0];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002681 for (int i = idx; i >= 0; i--) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002682 if (subject[i] != pattern_first_char) continue;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002683 int j = 1;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002684 while (j < pattern_length) {
2685 if (pattern[j] != subject[i+j]) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002686 break;
2687 }
2688 j++;
2689 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002690 if (j == pattern_length) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002691 return i;
2692 }
2693 }
2694 return -1;
2695}
2696
lrn@chromium.org303ada72010-10-27 09:33:13 +00002697static MaybeObject* Runtime_StringLastIndexOf(Arguments args) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002698 HandleScope scope; // create a new handle scope
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002699 ASSERT(args.length() == 3);
2700
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002701 CONVERT_ARG_CHECKED(String, sub, 0);
2702 CONVERT_ARG_CHECKED(String, pat, 1);
2703
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002704 Object* index = args[2];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002705 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002706 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002707
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002708 uint32_t pat_length = pat->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002709 uint32_t sub_length = sub->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002710
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002711 if (start_index + pat_length > sub_length) {
2712 start_index = sub_length - pat_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +00002713 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002714
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002715 if (pat_length == 0) {
2716 return Smi::FromInt(start_index);
2717 }
2718
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002719 if (!sub->IsFlat()) FlattenString(sub);
2720 if (!pat->IsFlat()) FlattenString(pat);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002721
2722 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
2723
2724 int position = -1;
2725
2726 if (pat->IsAsciiRepresentation()) {
2727 Vector<const char> pat_vector = pat->ToAsciiVector();
2728 if (sub->IsAsciiRepresentation()) {
2729 position = StringMatchBackwards(sub->ToAsciiVector(),
2730 pat_vector,
2731 start_index);
2732 } else {
2733 position = StringMatchBackwards(sub->ToUC16Vector(),
2734 pat_vector,
2735 start_index);
2736 }
2737 } else {
2738 Vector<const uc16> pat_vector = pat->ToUC16Vector();
2739 if (sub->IsAsciiRepresentation()) {
2740 position = StringMatchBackwards(sub->ToAsciiVector(),
2741 pat_vector,
2742 start_index);
2743 } else {
2744 position = StringMatchBackwards(sub->ToUC16Vector(),
2745 pat_vector,
2746 start_index);
2747 }
2748 }
2749
2750 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002751}
2752
2753
lrn@chromium.org303ada72010-10-27 09:33:13 +00002754static MaybeObject* Runtime_StringLocaleCompare(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002755 NoHandleAllocation ha;
2756 ASSERT(args.length() == 2);
2757
2758 CONVERT_CHECKED(String, str1, args[0]);
2759 CONVERT_CHECKED(String, str2, args[1]);
2760
2761 if (str1 == str2) return Smi::FromInt(0); // Equal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002762 int str1_length = str1->length();
2763 int str2_length = str2->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002764
2765 // Decide trivial cases without flattening.
2766 if (str1_length == 0) {
2767 if (str2_length == 0) return Smi::FromInt(0); // Equal.
2768 return Smi::FromInt(-str2_length);
2769 } else {
2770 if (str2_length == 0) return Smi::FromInt(str1_length);
2771 }
2772
2773 int end = str1_length < str2_length ? str1_length : str2_length;
2774
2775 // No need to flatten if we are going to find the answer on the first
2776 // character. At this point we know there is at least one character
2777 // in each string, due to the trivial case handling above.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002778 int d = str1->Get(0) - str2->Get(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002779 if (d != 0) return Smi::FromInt(d);
2780
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002781 str1->TryFlatten();
2782 str2->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002783
2784 static StringInputBuffer buf1;
2785 static StringInputBuffer buf2;
2786
2787 buf1.Reset(str1);
2788 buf2.Reset(str2);
2789
2790 for (int i = 0; i < end; i++) {
2791 uint16_t char1 = buf1.GetNext();
2792 uint16_t char2 = buf2.GetNext();
2793 if (char1 != char2) return Smi::FromInt(char1 - char2);
2794 }
2795
2796 return Smi::FromInt(str1_length - str2_length);
2797}
2798
2799
lrn@chromium.org303ada72010-10-27 09:33:13 +00002800static MaybeObject* Runtime_SubString(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002801 NoHandleAllocation ha;
2802 ASSERT(args.length() == 3);
2803
2804 CONVERT_CHECKED(String, value, args[0]);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002805 Object* from = args[1];
2806 Object* to = args[2];
2807 int start, end;
2808 // We have a fast integer-only case here to avoid a conversion to double in
2809 // the common case where from and to are Smis.
2810 if (from->IsSmi() && to->IsSmi()) {
2811 start = Smi::cast(from)->value();
2812 end = Smi::cast(to)->value();
2813 } else {
2814 CONVERT_DOUBLE_CHECKED(from_number, from);
2815 CONVERT_DOUBLE_CHECKED(to_number, to);
2816 start = FastD2I(from_number);
2817 end = FastD2I(to_number);
2818 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002819 RUNTIME_ASSERT(end >= start);
2820 RUNTIME_ASSERT(start >= 0);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00002821 RUNTIME_ASSERT(end <= value->length());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002822 Counters::sub_string_runtime.Increment();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002823 return value->SubString(start, end);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002824}
2825
2826
lrn@chromium.org303ada72010-10-27 09:33:13 +00002827static MaybeObject* Runtime_StringMatch(Arguments args) {
ager@chromium.org41826e72009-03-30 13:30:57 +00002828 ASSERT_EQ(3, args.length());
2829
2830 CONVERT_ARG_CHECKED(String, subject, 0);
2831 CONVERT_ARG_CHECKED(JSRegExp, regexp, 1);
2832 CONVERT_ARG_CHECKED(JSArray, regexp_info, 2);
2833 HandleScope handles;
2834
2835 Handle<Object> match = RegExpImpl::Exec(regexp, subject, 0, regexp_info);
2836
2837 if (match.is_null()) {
2838 return Failure::Exception();
2839 }
2840 if (match->IsNull()) {
2841 return Heap::null_value();
2842 }
2843 int length = subject->length();
2844
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00002845 CompilationZoneScope zone_space(DELETE_ON_EXIT);
ager@chromium.org41826e72009-03-30 13:30:57 +00002846 ZoneList<int> offsets(8);
2847 do {
2848 int start;
2849 int end;
2850 {
2851 AssertNoAllocation no_alloc;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002852 FixedArray* elements = FixedArray::cast(regexp_info->elements());
ager@chromium.org41826e72009-03-30 13:30:57 +00002853 start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value();
2854 end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value();
2855 }
2856 offsets.Add(start);
2857 offsets.Add(end);
2858 int index = start < end ? end : end + 1;
2859 if (index > length) break;
2860 match = RegExpImpl::Exec(regexp, subject, index, regexp_info);
2861 if (match.is_null()) {
2862 return Failure::Exception();
2863 }
2864 } while (!match->IsNull());
2865 int matches = offsets.length() / 2;
2866 Handle<FixedArray> elements = Factory::NewFixedArray(matches);
2867 for (int i = 0; i < matches ; i++) {
2868 int from = offsets.at(i * 2);
2869 int to = offsets.at(i * 2 + 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002870 Handle<String> match = Factory::NewSubString(subject, from, to);
2871 elements->set(i, *match);
ager@chromium.org41826e72009-03-30 13:30:57 +00002872 }
2873 Handle<JSArray> result = Factory::NewJSArrayWithElements(elements);
2874 result->set_length(Smi::FromInt(matches));
2875 return *result;
2876}
2877
2878
lrn@chromium.org25156de2010-04-06 13:10:27 +00002879// Two smis before and after the match, for very long strings.
2880const int kMaxBuilderEntriesPerRegExpMatch = 5;
2881
2882
2883static void SetLastMatchInfoNoCaptures(Handle<String> subject,
2884 Handle<JSArray> last_match_info,
2885 int match_start,
2886 int match_end) {
2887 // Fill last_match_info with a single capture.
2888 last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead);
2889 AssertNoAllocation no_gc;
2890 FixedArray* elements = FixedArray::cast(last_match_info->elements());
2891 RegExpImpl::SetLastCaptureCount(elements, 2);
2892 RegExpImpl::SetLastInput(elements, *subject);
2893 RegExpImpl::SetLastSubject(elements, *subject);
2894 RegExpImpl::SetCapture(elements, 0, match_start);
2895 RegExpImpl::SetCapture(elements, 1, match_end);
2896}
2897
2898
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002899template <typename SubjectChar, typename PatternChar>
2900static bool SearchStringMultiple(Vector<const SubjectChar> subject,
2901 Vector<const PatternChar> pattern,
2902 String* pattern_string,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002903 FixedArrayBuilder* builder,
2904 int* match_pos) {
2905 int pos = *match_pos;
2906 int subject_length = subject.length();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002907 int pattern_length = pattern.length();
lrn@chromium.org25156de2010-04-06 13:10:27 +00002908 int max_search_start = subject_length - pattern_length;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002909 StringSearch<PatternChar, SubjectChar> search(pattern);
2910 while (pos <= max_search_start) {
2911 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
2912 *match_pos = pos;
2913 return false;
2914 }
2915 // Position of end of previous match.
2916 int match_end = pos + pattern_length;
2917 int new_pos = search.Search(subject, match_end);
2918 if (new_pos >= 0) {
2919 // A match.
2920 if (new_pos > match_end) {
2921 ReplacementStringBuilder::AddSubjectSlice(builder,
2922 match_end,
2923 new_pos);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002924 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002925 pos = new_pos;
2926 builder->Add(pattern_string);
2927 } else {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002928 break;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002929 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00002930 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002931
lrn@chromium.org25156de2010-04-06 13:10:27 +00002932 if (pos < max_search_start) {
2933 ReplacementStringBuilder::AddSubjectSlice(builder,
2934 pos + pattern_length,
2935 subject_length);
2936 }
2937 *match_pos = pos;
2938 return true;
2939}
2940
2941
2942static bool SearchStringMultiple(Handle<String> subject,
2943 Handle<String> pattern,
2944 Handle<JSArray> last_match_info,
2945 FixedArrayBuilder* builder) {
2946 ASSERT(subject->IsFlat());
2947 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002948
2949 // Treating as if a previous match was before first character.
2950 int match_pos = -pattern->length();
2951
2952 for (;;) { // Break when search complete.
2953 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
2954 AssertNoAllocation no_gc;
2955 if (subject->IsAsciiRepresentation()) {
2956 Vector<const char> subject_vector = subject->ToAsciiVector();
2957 if (pattern->IsAsciiRepresentation()) {
2958 if (SearchStringMultiple(subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002959 pattern->ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002960 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002961 builder,
2962 &match_pos)) break;
2963 } else {
2964 if (SearchStringMultiple(subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002965 pattern->ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002966 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002967 builder,
2968 &match_pos)) break;
2969 }
2970 } else {
2971 Vector<const uc16> subject_vector = subject->ToUC16Vector();
2972 if (pattern->IsAsciiRepresentation()) {
2973 if (SearchStringMultiple(subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002974 pattern->ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002975 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002976 builder,
2977 &match_pos)) break;
2978 } else {
2979 if (SearchStringMultiple(subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002980 pattern->ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002981 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002982 builder,
2983 &match_pos)) break;
2984 }
2985 }
2986 }
2987
2988 if (match_pos >= 0) {
2989 SetLastMatchInfoNoCaptures(subject,
2990 last_match_info,
2991 match_pos,
2992 match_pos + pattern->length());
2993 return true;
2994 }
2995 return false; // No matches at all.
2996}
2997
2998
2999static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple(
3000 Handle<String> subject,
3001 Handle<JSRegExp> regexp,
3002 Handle<JSArray> last_match_array,
3003 FixedArrayBuilder* builder) {
3004 ASSERT(subject->IsFlat());
3005 int match_start = -1;
3006 int match_end = 0;
3007 int pos = 0;
3008 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3009 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3010
3011 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003012 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003013 int subject_length = subject->length();
3014
3015 for (;;) { // Break on failure, return on exception.
3016 RegExpImpl::IrregexpResult result =
3017 RegExpImpl::IrregexpExecOnce(regexp,
3018 subject,
3019 pos,
3020 register_vector);
3021 if (result == RegExpImpl::RE_SUCCESS) {
3022 match_start = register_vector[0];
3023 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3024 if (match_end < match_start) {
3025 ReplacementStringBuilder::AddSubjectSlice(builder,
3026 match_end,
3027 match_start);
3028 }
3029 match_end = register_vector[1];
3030 HandleScope loop_scope;
3031 builder->Add(*Factory::NewSubString(subject, match_start, match_end));
3032 if (match_start != match_end) {
3033 pos = match_end;
3034 } else {
3035 pos = match_end + 1;
3036 if (pos > subject_length) break;
3037 }
3038 } else if (result == RegExpImpl::RE_FAILURE) {
3039 break;
3040 } else {
3041 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3042 return result;
3043 }
3044 }
3045
3046 if (match_start >= 0) {
3047 if (match_end < subject_length) {
3048 ReplacementStringBuilder::AddSubjectSlice(builder,
3049 match_end,
3050 subject_length);
3051 }
3052 SetLastMatchInfoNoCaptures(subject,
3053 last_match_array,
3054 match_start,
3055 match_end);
3056 return RegExpImpl::RE_SUCCESS;
3057 } else {
3058 return RegExpImpl::RE_FAILURE; // No matches at all.
3059 }
3060}
3061
3062
3063static RegExpImpl::IrregexpResult SearchRegExpMultiple(
3064 Handle<String> subject,
3065 Handle<JSRegExp> regexp,
3066 Handle<JSArray> last_match_array,
3067 FixedArrayBuilder* builder) {
3068
3069 ASSERT(subject->IsFlat());
3070 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3071 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3072
3073 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003074 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003075
3076 RegExpImpl::IrregexpResult result =
3077 RegExpImpl::IrregexpExecOnce(regexp,
3078 subject,
3079 0,
3080 register_vector);
3081
3082 int capture_count = regexp->CaptureCount();
3083 int subject_length = subject->length();
3084
3085 // Position to search from.
3086 int pos = 0;
3087 // End of previous match. Differs from pos if match was empty.
3088 int match_end = 0;
3089 if (result == RegExpImpl::RE_SUCCESS) {
3090 // Need to keep a copy of the previous match for creating last_match_info
3091 // at the end, so we have two vectors that we swap between.
3092 OffsetsVector registers2(required_registers);
3093 Vector<int> prev_register_vector(registers2.vector(), registers2.length());
3094
3095 do {
3096 int match_start = register_vector[0];
3097 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3098 if (match_end < match_start) {
3099 ReplacementStringBuilder::AddSubjectSlice(builder,
3100 match_end,
3101 match_start);
3102 }
3103 match_end = register_vector[1];
3104
3105 {
3106 // Avoid accumulating new handles inside loop.
3107 HandleScope temp_scope;
3108 // Arguments array to replace function is match, captures, index and
3109 // subject, i.e., 3 + capture count in total.
3110 Handle<FixedArray> elements = Factory::NewFixedArray(3 + capture_count);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003111 Handle<String> match = Factory::NewSubString(subject,
3112 match_start,
3113 match_end);
3114 elements->set(0, *match);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003115 for (int i = 1; i <= capture_count; i++) {
3116 int start = register_vector[i * 2];
3117 if (start >= 0) {
3118 int end = register_vector[i * 2 + 1];
3119 ASSERT(start <= end);
3120 Handle<String> substring = Factory::NewSubString(subject,
3121 start,
3122 end);
3123 elements->set(i, *substring);
3124 } else {
3125 ASSERT(register_vector[i * 2 + 1] < 0);
3126 elements->set(i, Heap::undefined_value());
3127 }
3128 }
3129 elements->set(capture_count + 1, Smi::FromInt(match_start));
3130 elements->set(capture_count + 2, *subject);
3131 builder->Add(*Factory::NewJSArrayWithElements(elements));
3132 }
3133 // Swap register vectors, so the last successful match is in
3134 // prev_register_vector.
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003135 Vector<int32_t> tmp = prev_register_vector;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003136 prev_register_vector = register_vector;
3137 register_vector = tmp;
3138
3139 if (match_end > match_start) {
3140 pos = match_end;
3141 } else {
3142 pos = match_end + 1;
3143 if (pos > subject_length) {
3144 break;
3145 }
3146 }
3147
3148 result = RegExpImpl::IrregexpExecOnce(regexp,
3149 subject,
3150 pos,
3151 register_vector);
3152 } while (result == RegExpImpl::RE_SUCCESS);
3153
3154 if (result != RegExpImpl::RE_EXCEPTION) {
3155 // Finished matching, with at least one match.
3156 if (match_end < subject_length) {
3157 ReplacementStringBuilder::AddSubjectSlice(builder,
3158 match_end,
3159 subject_length);
3160 }
3161
3162 int last_match_capture_count = (capture_count + 1) * 2;
3163 int last_match_array_size =
3164 last_match_capture_count + RegExpImpl::kLastMatchOverhead;
3165 last_match_array->EnsureSize(last_match_array_size);
3166 AssertNoAllocation no_gc;
3167 FixedArray* elements = FixedArray::cast(last_match_array->elements());
3168 RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count);
3169 RegExpImpl::SetLastSubject(elements, *subject);
3170 RegExpImpl::SetLastInput(elements, *subject);
3171 for (int i = 0; i < last_match_capture_count; i++) {
3172 RegExpImpl::SetCapture(elements, i, prev_register_vector[i]);
3173 }
3174 return RegExpImpl::RE_SUCCESS;
3175 }
3176 }
3177 // No matches at all, return failure or exception result directly.
3178 return result;
3179}
3180
3181
lrn@chromium.org303ada72010-10-27 09:33:13 +00003182static MaybeObject* Runtime_RegExpExecMultiple(Arguments args) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003183 ASSERT(args.length() == 4);
3184 HandleScope handles;
3185
3186 CONVERT_ARG_CHECKED(String, subject, 1);
3187 if (!subject->IsFlat()) { FlattenString(subject); }
3188 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
3189 CONVERT_ARG_CHECKED(JSArray, last_match_info, 2);
3190 CONVERT_ARG_CHECKED(JSArray, result_array, 3);
3191
3192 ASSERT(last_match_info->HasFastElements());
3193 ASSERT(regexp->GetFlags().is_global());
3194 Handle<FixedArray> result_elements;
3195 if (result_array->HasFastElements()) {
3196 result_elements =
3197 Handle<FixedArray>(FixedArray::cast(result_array->elements()));
3198 } else {
3199 result_elements = Factory::NewFixedArrayWithHoles(16);
3200 }
3201 FixedArrayBuilder builder(result_elements);
3202
3203 if (regexp->TypeTag() == JSRegExp::ATOM) {
3204 Handle<String> pattern(
3205 String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003206 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003207 if (SearchStringMultiple(subject, pattern, last_match_info, &builder)) {
3208 return *builder.ToJSArray(result_array);
3209 }
3210 return Heap::null_value();
3211 }
3212
3213 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
3214
3215 RegExpImpl::IrregexpResult result;
3216 if (regexp->CaptureCount() == 0) {
3217 result = SearchRegExpNoCaptureMultiple(subject,
3218 regexp,
3219 last_match_info,
3220 &builder);
3221 } else {
3222 result = SearchRegExpMultiple(subject, regexp, last_match_info, &builder);
3223 }
3224 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array);
3225 if (result == RegExpImpl::RE_FAILURE) return Heap::null_value();
3226 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3227 return Failure::Exception();
3228}
3229
3230
lrn@chromium.org303ada72010-10-27 09:33:13 +00003231static MaybeObject* Runtime_NumberToRadixString(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003232 NoHandleAllocation ha;
3233 ASSERT(args.length() == 2);
3234
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003235 // Fast case where the result is a one character string.
3236 if (args[0]->IsSmi() && args[1]->IsSmi()) {
3237 int value = Smi::cast(args[0])->value();
3238 int radix = Smi::cast(args[1])->value();
3239 if (value >= 0 && value < radix) {
3240 RUNTIME_ASSERT(radix <= 36);
3241 // Character array used for conversion.
3242 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
3243 return Heap::LookupSingleCharacterStringFromCode(kCharTable[value]);
3244 }
3245 }
3246
3247 // Slow case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003248 CONVERT_DOUBLE_CHECKED(value, args[0]);
3249 if (isnan(value)) {
3250 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
3251 }
3252 if (isinf(value)) {
3253 if (value < 0) {
3254 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
3255 }
3256 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
3257 }
3258 CONVERT_DOUBLE_CHECKED(radix_number, args[1]);
3259 int radix = FastD2I(radix_number);
3260 RUNTIME_ASSERT(2 <= radix && radix <= 36);
3261 char* str = DoubleToRadixCString(value, radix);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003262 MaybeObject* result = Heap::AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003263 DeleteArray(str);
3264 return result;
3265}
3266
3267
lrn@chromium.org303ada72010-10-27 09:33:13 +00003268static MaybeObject* Runtime_NumberToFixed(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003269 NoHandleAllocation ha;
3270 ASSERT(args.length() == 2);
3271
3272 CONVERT_DOUBLE_CHECKED(value, args[0]);
3273 if (isnan(value)) {
3274 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
3275 }
3276 if (isinf(value)) {
3277 if (value < 0) {
3278 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
3279 }
3280 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
3281 }
3282 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3283 int f = FastD2I(f_number);
3284 RUNTIME_ASSERT(f >= 0);
3285 char* str = DoubleToFixedCString(value, f);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003286 MaybeObject* result = Heap::AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003287 DeleteArray(str);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003288 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003289}
3290
3291
lrn@chromium.org303ada72010-10-27 09:33:13 +00003292static MaybeObject* Runtime_NumberToExponential(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003293 NoHandleAllocation ha;
3294 ASSERT(args.length() == 2);
3295
3296 CONVERT_DOUBLE_CHECKED(value, args[0]);
3297 if (isnan(value)) {
3298 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
3299 }
3300 if (isinf(value)) {
3301 if (value < 0) {
3302 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
3303 }
3304 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
3305 }
3306 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3307 int f = FastD2I(f_number);
3308 RUNTIME_ASSERT(f >= -1 && f <= 20);
3309 char* str = DoubleToExponentialCString(value, f);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003310 MaybeObject* result = Heap::AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003311 DeleteArray(str);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003312 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003313}
3314
3315
lrn@chromium.org303ada72010-10-27 09:33:13 +00003316static MaybeObject* Runtime_NumberToPrecision(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003317 NoHandleAllocation ha;
3318 ASSERT(args.length() == 2);
3319
3320 CONVERT_DOUBLE_CHECKED(value, args[0]);
3321 if (isnan(value)) {
3322 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
3323 }
3324 if (isinf(value)) {
3325 if (value < 0) {
3326 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
3327 }
3328 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
3329 }
3330 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3331 int f = FastD2I(f_number);
3332 RUNTIME_ASSERT(f >= 1 && f <= 21);
3333 char* str = DoubleToPrecisionCString(value, f);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003334 MaybeObject* result = Heap::AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003335 DeleteArray(str);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003336 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003337}
3338
3339
3340// Returns a single character string where first character equals
3341// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003342static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003343 if (index < static_cast<uint32_t>(string->length())) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003344 string->TryFlatten();
ager@chromium.org870a0b62008-11-04 11:43:05 +00003345 return LookupSingleCharacterStringFromCode(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003346 string->Get(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003347 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003348 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003349}
3350
3351
lrn@chromium.org303ada72010-10-27 09:33:13 +00003352MaybeObject* Runtime::GetElementOrCharAt(Handle<Object> object,
3353 uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003354 // Handle [] indexing on Strings
3355 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003356 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
3357 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003358 }
3359
3360 // Handle [] indexing on String objects
3361 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003362 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
3363 Handle<Object> result =
3364 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
3365 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003366 }
3367
3368 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003369 Handle<Object> prototype = GetPrototype(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003370 return prototype->GetElement(index);
3371 }
3372
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003373 return GetElement(object, index);
3374}
3375
3376
lrn@chromium.org303ada72010-10-27 09:33:13 +00003377MaybeObject* Runtime::GetElement(Handle<Object> object, uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003378 return object->GetElement(index);
3379}
3380
3381
lrn@chromium.org303ada72010-10-27 09:33:13 +00003382MaybeObject* Runtime::GetObjectProperty(Handle<Object> object,
3383 Handle<Object> key) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003384 HandleScope scope;
3385
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003386 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003387 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003388 Handle<Object> error =
3389 Factory::NewTypeError("non_object_property_load",
3390 HandleVector(args, 2));
3391 return Top::Throw(*error);
3392 }
3393
3394 // Check if the given key is an array index.
3395 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003396 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003397 return GetElementOrCharAt(object, index);
3398 }
3399
3400 // Convert the key to a string - possibly by calling back into JavaScript.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003401 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003402 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003403 name = Handle<String>::cast(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003404 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003405 bool has_pending_exception = false;
3406 Handle<Object> converted =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003407 Execution::ToString(key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003408 if (has_pending_exception) return Failure::Exception();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003409 name = Handle<String>::cast(converted);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003410 }
3411
ager@chromium.org32912102009-01-16 10:38:43 +00003412 // Check if the name is trivially convertible to an index and get
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003413 // the element if so.
3414 if (name->AsArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003415 return GetElementOrCharAt(object, index);
3416 } else {
3417 PropertyAttributes attr;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003418 return object->GetProperty(*name, &attr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003419 }
3420}
3421
3422
lrn@chromium.org303ada72010-10-27 09:33:13 +00003423static MaybeObject* Runtime_GetProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003424 NoHandleAllocation ha;
3425 ASSERT(args.length() == 2);
3426
3427 Handle<Object> object = args.at<Object>(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003428 Handle<Object> key = args.at<Object>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003429
3430 return Runtime::GetObjectProperty(object, key);
3431}
3432
3433
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003434// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003435static MaybeObject* Runtime_KeyedGetProperty(Arguments args) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00003436 NoHandleAllocation ha;
3437 ASSERT(args.length() == 2);
3438
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003439 // Fast cases for getting named properties of the receiver JSObject
ager@chromium.org8bb60582008-12-11 12:02:20 +00003440 // itself.
3441 //
3442 // The global proxy objects has to be excluded since LocalLookup on
ager@chromium.org32912102009-01-16 10:38:43 +00003443 // the global proxy object can return a valid result even though the
ager@chromium.org8bb60582008-12-11 12:02:20 +00003444 // global proxy object never has properties. This is the case
3445 // because the global proxy object forwards everything to its hidden
3446 // prototype including local lookups.
3447 //
3448 // Additionally, we need to make sure that we do not cache results
3449 // for objects that require access checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003450 if (args[0]->IsJSObject() &&
3451 !args[0]->IsJSGlobalProxy() &&
ager@chromium.org8bb60582008-12-11 12:02:20 +00003452 !args[0]->IsAccessCheckNeeded() &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003453 args[1]->IsString()) {
3454 JSObject* receiver = JSObject::cast(args[0]);
3455 String* key = String::cast(args[1]);
3456 if (receiver->HasFastProperties()) {
3457 // Attempt to use lookup cache.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003458 Map* receiver_map = receiver->map();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00003459 int offset = KeyedLookupCache::Lookup(receiver_map, key);
3460 if (offset != -1) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003461 Object* value = receiver->FastPropertyAt(offset);
3462 return value->IsTheHole() ? Heap::undefined_value() : value;
3463 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003464 // Lookup cache miss. Perform lookup and update the cache if appropriate.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003465 LookupResult result;
3466 receiver->LocalLookup(key, &result);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00003467 if (result.IsProperty() && result.type() == FIELD) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003468 int offset = result.GetFieldIndex();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00003469 KeyedLookupCache::Update(receiver_map, key, offset);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003470 return receiver->FastPropertyAt(offset);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003471 }
3472 } else {
3473 // Attempt dictionary lookup.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00003474 StringDictionary* dictionary = receiver->property_dictionary();
3475 int entry = dictionary->FindEntry(key);
3476 if ((entry != StringDictionary::kNotFound) &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003477 (dictionary->DetailsAt(entry).type() == NORMAL)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003478 Object* value = dictionary->ValueAt(entry);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003479 if (!receiver->IsGlobalObject()) return value;
3480 value = JSGlobalPropertyCell::cast(value)->value();
3481 if (!value->IsTheHole()) return value;
3482 // If value is the hole do the general lookup.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003483 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00003484 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003485 } else if (args[0]->IsString() && args[1]->IsSmi()) {
3486 // Fast case for string indexing using [] with a smi index.
3487 HandleScope scope;
3488 Handle<String> str = args.at<String>(0);
3489 int index = Smi::cast(args[1])->value();
3490 Handle<Object> result = GetCharAt(str, index);
3491 return *result;
ager@chromium.org7c537e22008-10-16 08:43:32 +00003492 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003493
3494 // Fall back to GetObjectProperty.
ager@chromium.org7c537e22008-10-16 08:43:32 +00003495 return Runtime::GetObjectProperty(args.at<Object>(0),
3496 args.at<Object>(1));
3497}
3498
3499
lrn@chromium.org303ada72010-10-27 09:33:13 +00003500static MaybeObject* Runtime_DefineOrRedefineAccessorProperty(Arguments args) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003501 ASSERT(args.length() == 5);
3502 HandleScope scope;
3503 CONVERT_ARG_CHECKED(JSObject, obj, 0);
3504 CONVERT_CHECKED(String, name, args[1]);
3505 CONVERT_CHECKED(Smi, flag_setter, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003506 Object* fun = args[3];
3507 RUNTIME_ASSERT(fun->IsJSFunction() || fun->IsUndefined());
ager@chromium.org5c838252010-02-19 08:53:10 +00003508 CONVERT_CHECKED(Smi, flag_attr, args[4]);
3509 int unchecked = flag_attr->value();
3510 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3511 RUNTIME_ASSERT(!obj->IsNull());
3512 LookupResult result;
3513 obj->LocalLookupRealNamedProperty(name, &result);
3514
3515 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
3516 // If an existing property is either FIELD, NORMAL or CONSTANT_FUNCTION
3517 // delete it to avoid running into trouble in DefineAccessor, which
3518 // handles this incorrectly if the property is readonly (does nothing)
3519 if (result.IsProperty() &&
3520 (result.type() == FIELD || result.type() == NORMAL
3521 || result.type() == CONSTANT_FUNCTION)) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003522 Object* ok;
3523 { MaybeObject* maybe_ok =
3524 obj->DeleteProperty(name, JSObject::NORMAL_DELETION);
3525 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
3526 }
ager@chromium.org5c838252010-02-19 08:53:10 +00003527 }
3528 return obj->DefineAccessor(name, flag_setter->value() == 0, fun, attr);
3529}
3530
lrn@chromium.org303ada72010-10-27 09:33:13 +00003531static MaybeObject* Runtime_DefineOrRedefineDataProperty(Arguments args) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003532 ASSERT(args.length() == 4);
3533 HandleScope scope;
3534 CONVERT_ARG_CHECKED(JSObject, js_object, 0);
3535 CONVERT_ARG_CHECKED(String, name, 1);
3536 Handle<Object> obj_value = args.at<Object>(2);
3537
3538 CONVERT_CHECKED(Smi, flag, args[3]);
3539 int unchecked = flag->value();
3540 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3541
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003542 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
3543
3544 // Check if this is an element.
3545 uint32_t index;
3546 bool is_element = name->AsArrayIndex(&index);
3547
3548 // Special case for elements if any of the flags are true.
3549 // If elements are in fast case we always implicitly assume that:
3550 // DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
3551 if (((unchecked & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0) &&
3552 is_element) {
3553 // Normalize the elements to enable attributes on the property.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003554 NormalizeElements(js_object);
3555 Handle<NumberDictionary> dictionary(js_object->element_dictionary());
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003556 // Make sure that we never go back to fast case.
3557 dictionary->set_requires_slow_elements();
3558 PropertyDetails details = PropertyDetails(attr, NORMAL);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003559 NumberDictionarySet(dictionary, index, obj_value, details);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003560 }
3561
ager@chromium.org5c838252010-02-19 08:53:10 +00003562 LookupResult result;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003563 js_object->LookupRealNamedProperty(*name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00003564
ager@chromium.org5c838252010-02-19 08:53:10 +00003565 // Take special care when attributes are different and there is already
3566 // a property. For simplicity we normalize the property which enables us
3567 // to not worry about changing the instance_descriptor and creating a new
3568 // map. The current version of SetObjectProperty does not handle attributes
3569 // correctly in the case where a property is a field and is reset with
3570 // new attributes.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003571 if (result.IsProperty() &&
3572 (attr != result.GetAttributes() || result.type() == CALLBACKS)) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003573 // New attributes - normalize to avoid writing to instance descriptor
lrn@chromium.org303ada72010-10-27 09:33:13 +00003574 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00003575 // Use IgnoreAttributes version since a readonly property may be
3576 // overridden and SetProperty does not allow this.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003577 return js_object->SetLocalPropertyIgnoreAttributes(*name,
3578 *obj_value,
3579 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00003580 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003581
ager@chromium.org5c838252010-02-19 08:53:10 +00003582 return Runtime::SetObjectProperty(js_object, name, obj_value, attr);
3583}
3584
3585
lrn@chromium.org303ada72010-10-27 09:33:13 +00003586MaybeObject* Runtime::SetObjectProperty(Handle<Object> object,
3587 Handle<Object> key,
3588 Handle<Object> value,
3589 PropertyAttributes attr) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003590 HandleScope scope;
3591
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003592 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003593 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003594 Handle<Object> error =
3595 Factory::NewTypeError("non_object_property_store",
3596 HandleVector(args, 2));
3597 return Top::Throw(*error);
3598 }
3599
3600 // If the object isn't a JavaScript object, we ignore the store.
3601 if (!object->IsJSObject()) return *value;
3602
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003603 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
3604
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003605 // Check if the given key is an array index.
3606 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003607 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003608 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
3609 // of a string using [] notation. We need to support this too in
3610 // JavaScript.
3611 // In the case of a String object we just need to redirect the assignment to
3612 // the underlying string if the index is in range. Since the underlying
3613 // string does nothing with the assignment then we can ignore such
3614 // assignments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003615 if (js_object->IsStringObjectWithCharacterAt(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003616 return *value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003617 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003618
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003619 Handle<Object> result = SetElement(js_object, index, value);
3620 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003621 return *value;
3622 }
3623
3624 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003625 Handle<Object> result;
3626 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003627 result = SetElement(js_object, index, value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003628 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003629 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003630 key_string->TryFlatten();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003631 result = SetProperty(js_object, key_string, value, attr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003632 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003633 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003634 return *value;
3635 }
3636
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003637 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003638 bool has_pending_exception = false;
3639 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
3640 if (has_pending_exception) return Failure::Exception();
3641 Handle<String> name = Handle<String>::cast(converted);
3642
3643 if (name->AsArrayIndex(&index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003644 return js_object->SetElement(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003645 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003646 return js_object->SetProperty(*name, *value, attr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003647 }
3648}
3649
3650
lrn@chromium.org303ada72010-10-27 09:33:13 +00003651MaybeObject* Runtime::ForceSetObjectProperty(Handle<JSObject> js_object,
3652 Handle<Object> key,
3653 Handle<Object> value,
3654 PropertyAttributes attr) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003655 HandleScope scope;
3656
3657 // Check if the given key is an array index.
3658 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003659 if (key->ToArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003660 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
3661 // of a string using [] notation. We need to support this too in
3662 // JavaScript.
3663 // In the case of a String object we just need to redirect the assignment to
3664 // the underlying string if the index is in range. Since the underlying
3665 // string does nothing with the assignment then we can ignore such
3666 // assignments.
3667 if (js_object->IsStringObjectWithCharacterAt(index)) {
3668 return *value;
3669 }
3670
3671 return js_object->SetElement(index, *value);
3672 }
3673
3674 if (key->IsString()) {
3675 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003676 return js_object->SetElement(index, *value);
3677 } else {
3678 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003679 key_string->TryFlatten();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003680 return js_object->SetLocalPropertyIgnoreAttributes(*key_string,
3681 *value,
3682 attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003683 }
3684 }
3685
3686 // Call-back into JavaScript to convert the key to a string.
3687 bool has_pending_exception = false;
3688 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
3689 if (has_pending_exception) return Failure::Exception();
3690 Handle<String> name = Handle<String>::cast(converted);
3691
3692 if (name->AsArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003693 return js_object->SetElement(index, *value);
3694 } else {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003695 return js_object->SetLocalPropertyIgnoreAttributes(*name, *value, attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003696 }
3697}
3698
3699
lrn@chromium.org303ada72010-10-27 09:33:13 +00003700MaybeObject* Runtime::ForceDeleteObjectProperty(Handle<JSObject> js_object,
3701 Handle<Object> key) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00003702 HandleScope scope;
3703
3704 // Check if the given key is an array index.
3705 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003706 if (key->ToArrayIndex(&index)) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00003707 // In Firefox/SpiderMonkey, Safari and Opera you can access the
3708 // characters of a string using [] notation. In the case of a
3709 // String object we just need to redirect the deletion to the
3710 // underlying string if the index is in range. Since the
3711 // underlying string does nothing with the deletion, we can ignore
3712 // such deletions.
3713 if (js_object->IsStringObjectWithCharacterAt(index)) {
3714 return Heap::true_value();
3715 }
3716
3717 return js_object->DeleteElement(index, JSObject::FORCE_DELETION);
3718 }
3719
3720 Handle<String> key_string;
3721 if (key->IsString()) {
3722 key_string = Handle<String>::cast(key);
3723 } else {
3724 // Call-back into JavaScript to convert the key to a string.
3725 bool has_pending_exception = false;
3726 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
3727 if (has_pending_exception) return Failure::Exception();
3728 key_string = Handle<String>::cast(converted);
3729 }
3730
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003731 key_string->TryFlatten();
ager@chromium.orge2902be2009-06-08 12:21:35 +00003732 return js_object->DeleteProperty(*key_string, JSObject::FORCE_DELETION);
3733}
3734
3735
lrn@chromium.org303ada72010-10-27 09:33:13 +00003736static MaybeObject* Runtime_SetProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003737 NoHandleAllocation ha;
3738 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
3739
3740 Handle<Object> object = args.at<Object>(0);
3741 Handle<Object> key = args.at<Object>(1);
3742 Handle<Object> value = args.at<Object>(2);
3743
3744 // Compute attributes.
3745 PropertyAttributes attributes = NONE;
3746 if (args.length() == 4) {
3747 CONVERT_CHECKED(Smi, value_obj, args[3]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003748 int unchecked_value = value_obj->value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003749 // Only attribute bits should be set.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003750 RUNTIME_ASSERT(
3751 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3752 attributes = static_cast<PropertyAttributes>(unchecked_value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003753 }
3754 return Runtime::SetObjectProperty(object, key, value, attributes);
3755}
3756
3757
3758// Set a local property, even if it is READ_ONLY. If the property does not
3759// exist, it will be added with attributes NONE.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003760static MaybeObject* Runtime_IgnoreAttributesAndSetProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003761 NoHandleAllocation ha;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003762 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003763 CONVERT_CHECKED(JSObject, object, args[0]);
3764 CONVERT_CHECKED(String, name, args[1]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003765 // Compute attributes.
3766 PropertyAttributes attributes = NONE;
3767 if (args.length() == 4) {
3768 CONVERT_CHECKED(Smi, value_obj, args[3]);
3769 int unchecked_value = value_obj->value();
3770 // Only attribute bits should be set.
3771 RUNTIME_ASSERT(
3772 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3773 attributes = static_cast<PropertyAttributes>(unchecked_value);
3774 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003775
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003776 return object->
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003777 SetLocalPropertyIgnoreAttributes(name, args[2], attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003778}
3779
3780
lrn@chromium.org303ada72010-10-27 09:33:13 +00003781static MaybeObject* Runtime_DeleteProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003782 NoHandleAllocation ha;
3783 ASSERT(args.length() == 2);
3784
3785 CONVERT_CHECKED(JSObject, object, args[0]);
3786 CONVERT_CHECKED(String, key, args[1]);
ager@chromium.orge2902be2009-06-08 12:21:35 +00003787 return object->DeleteProperty(key, JSObject::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003788}
3789
3790
ager@chromium.org9085a012009-05-11 19:22:57 +00003791static Object* HasLocalPropertyImplementation(Handle<JSObject> object,
3792 Handle<String> key) {
3793 if (object->HasLocalProperty(*key)) return Heap::true_value();
3794 // Handle hidden prototypes. If there's a hidden prototype above this thing
3795 // then we have to check it for properties, because they are supposed to
3796 // look like they are on this object.
3797 Handle<Object> proto(object->GetPrototype());
3798 if (proto->IsJSObject() &&
3799 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
3800 return HasLocalPropertyImplementation(Handle<JSObject>::cast(proto), key);
3801 }
3802 return Heap::false_value();
3803}
3804
3805
lrn@chromium.org303ada72010-10-27 09:33:13 +00003806static MaybeObject* Runtime_HasLocalProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003807 NoHandleAllocation ha;
3808 ASSERT(args.length() == 2);
3809 CONVERT_CHECKED(String, key, args[1]);
3810
ager@chromium.org9085a012009-05-11 19:22:57 +00003811 Object* obj = args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003812 // Only JS objects can have properties.
ager@chromium.org9085a012009-05-11 19:22:57 +00003813 if (obj->IsJSObject()) {
3814 JSObject* object = JSObject::cast(obj);
3815 // Fast case - no interceptors.
3816 if (object->HasRealNamedProperty(key)) return Heap::true_value();
3817 // Slow case. Either it's not there or we have an interceptor. We should
3818 // have handles for this kind of deal.
3819 HandleScope scope;
3820 return HasLocalPropertyImplementation(Handle<JSObject>(object),
3821 Handle<String>(key));
3822 } else if (obj->IsString()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003823 // Well, there is one exception: Handle [] on strings.
3824 uint32_t index;
3825 if (key->AsArrayIndex(&index)) {
ager@chromium.org9085a012009-05-11 19:22:57 +00003826 String* string = String::cast(obj);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003827 if (index < static_cast<uint32_t>(string->length()))
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003828 return Heap::true_value();
3829 }
3830 }
3831 return Heap::false_value();
3832}
3833
3834
lrn@chromium.org303ada72010-10-27 09:33:13 +00003835static MaybeObject* Runtime_HasProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003836 NoHandleAllocation na;
3837 ASSERT(args.length() == 2);
3838
3839 // Only JS objects can have properties.
3840 if (args[0]->IsJSObject()) {
3841 JSObject* object = JSObject::cast(args[0]);
3842 CONVERT_CHECKED(String, key, args[1]);
3843 if (object->HasProperty(key)) return Heap::true_value();
3844 }
3845 return Heap::false_value();
3846}
3847
3848
lrn@chromium.org303ada72010-10-27 09:33:13 +00003849static MaybeObject* Runtime_HasElement(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003850 NoHandleAllocation na;
3851 ASSERT(args.length() == 2);
3852
3853 // Only JS objects can have elements.
3854 if (args[0]->IsJSObject()) {
3855 JSObject* object = JSObject::cast(args[0]);
3856 CONVERT_CHECKED(Smi, index_obj, args[1]);
3857 uint32_t index = index_obj->value();
3858 if (object->HasElement(index)) return Heap::true_value();
3859 }
3860 return Heap::false_value();
3861}
3862
3863
lrn@chromium.org303ada72010-10-27 09:33:13 +00003864static MaybeObject* Runtime_IsPropertyEnumerable(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003865 NoHandleAllocation ha;
3866 ASSERT(args.length() == 2);
3867
3868 CONVERT_CHECKED(JSObject, object, args[0]);
3869 CONVERT_CHECKED(String, key, args[1]);
3870
3871 uint32_t index;
3872 if (key->AsArrayIndex(&index)) {
3873 return Heap::ToBoolean(object->HasElement(index));
3874 }
3875
ager@chromium.org870a0b62008-11-04 11:43:05 +00003876 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
3877 return Heap::ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003878}
3879
3880
lrn@chromium.org303ada72010-10-27 09:33:13 +00003881static MaybeObject* Runtime_GetPropertyNames(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003882 HandleScope scope;
3883 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00003884 CONVERT_ARG_CHECKED(JSObject, object, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003885 return *GetKeysFor(object);
3886}
3887
3888
3889// Returns either a FixedArray as Runtime_GetPropertyNames,
3890// or, if the given object has an enum cache that contains
3891// all enumerable properties of the object and its prototypes
3892// have none, the map of the object. This is used to speed up
3893// the check for deletions during a for-in.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003894static MaybeObject* Runtime_GetPropertyNamesFast(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003895 ASSERT(args.length() == 1);
3896
3897 CONVERT_CHECKED(JSObject, raw_object, args[0]);
3898
3899 if (raw_object->IsSimpleEnum()) return raw_object->map();
3900
3901 HandleScope scope;
3902 Handle<JSObject> object(raw_object);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00003903 Handle<FixedArray> content = GetKeysInFixedArrayFor(object,
3904 INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003905
3906 // Test again, since cache may have been built by preceding call.
3907 if (object->IsSimpleEnum()) return object->map();
3908
3909 return *content;
3910}
3911
3912
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003913// Find the length of the prototype chain that is to to handled as one. If a
3914// prototype object is hidden it is to be viewed as part of the the object it
3915// is prototype for.
3916static int LocalPrototypeChainLength(JSObject* obj) {
3917 int count = 1;
3918 Object* proto = obj->GetPrototype();
3919 while (proto->IsJSObject() &&
3920 JSObject::cast(proto)->map()->is_hidden_prototype()) {
3921 count++;
3922 proto = JSObject::cast(proto)->GetPrototype();
3923 }
3924 return count;
3925}
3926
3927
3928// Return the names of the local named properties.
3929// args[0]: object
lrn@chromium.org303ada72010-10-27 09:33:13 +00003930static MaybeObject* Runtime_GetLocalPropertyNames(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003931 HandleScope scope;
3932 ASSERT(args.length() == 1);
3933 if (!args[0]->IsJSObject()) {
3934 return Heap::undefined_value();
3935 }
3936 CONVERT_ARG_CHECKED(JSObject, obj, 0);
3937
3938 // Skip the global proxy as it has no properties and always delegates to the
3939 // real global object.
3940 if (obj->IsJSGlobalProxy()) {
3941 // Only collect names if access is permitted.
3942 if (obj->IsAccessCheckNeeded() &&
3943 !Top::MayNamedAccess(*obj, Heap::undefined_value(), v8::ACCESS_KEYS)) {
3944 Top::ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
3945 return *Factory::NewJSArray(0);
3946 }
3947 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
3948 }
3949
3950 // Find the number of objects making up this.
3951 int length = LocalPrototypeChainLength(*obj);
3952
3953 // Find the number of local properties for each of the objects.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00003954 ScopedVector<int> local_property_count(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003955 int total_property_count = 0;
3956 Handle<JSObject> jsproto = obj;
3957 for (int i = 0; i < length; i++) {
3958 // Only collect names if access is permitted.
3959 if (jsproto->IsAccessCheckNeeded() &&
3960 !Top::MayNamedAccess(*jsproto,
3961 Heap::undefined_value(),
3962 v8::ACCESS_KEYS)) {
3963 Top::ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
3964 return *Factory::NewJSArray(0);
3965 }
3966 int n;
3967 n = jsproto->NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE));
3968 local_property_count[i] = n;
3969 total_property_count += n;
3970 if (i < length - 1) {
3971 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
3972 }
3973 }
3974
3975 // Allocate an array with storage for all the property names.
3976 Handle<FixedArray> names = Factory::NewFixedArray(total_property_count);
3977
3978 // Get the property names.
3979 jsproto = obj;
3980 int proto_with_hidden_properties = 0;
3981 for (int i = 0; i < length; i++) {
3982 jsproto->GetLocalPropertyNames(*names,
3983 i == 0 ? 0 : local_property_count[i - 1]);
3984 if (!GetHiddenProperties(jsproto, false)->IsUndefined()) {
3985 proto_with_hidden_properties++;
3986 }
3987 if (i < length - 1) {
3988 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
3989 }
3990 }
3991
3992 // Filter out name of hidden propeties object.
3993 if (proto_with_hidden_properties > 0) {
3994 Handle<FixedArray> old_names = names;
3995 names = Factory::NewFixedArray(
3996 names->length() - proto_with_hidden_properties);
3997 int dest_pos = 0;
3998 for (int i = 0; i < total_property_count; i++) {
3999 Object* name = old_names->get(i);
4000 if (name == Heap::hidden_symbol()) {
4001 continue;
4002 }
4003 names->set(dest_pos++, name);
4004 }
4005 }
4006
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004007 return *Factory::NewJSArrayWithElements(names);
4008}
4009
4010
4011// Return the names of the local indexed properties.
4012// args[0]: object
lrn@chromium.org303ada72010-10-27 09:33:13 +00004013static MaybeObject* Runtime_GetLocalElementNames(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004014 HandleScope scope;
4015 ASSERT(args.length() == 1);
4016 if (!args[0]->IsJSObject()) {
4017 return Heap::undefined_value();
4018 }
4019 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4020
4021 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
4022 Handle<FixedArray> names = Factory::NewFixedArray(n);
4023 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
4024 return *Factory::NewJSArrayWithElements(names);
4025}
4026
4027
4028// Return information on whether an object has a named or indexed interceptor.
4029// args[0]: object
lrn@chromium.org303ada72010-10-27 09:33:13 +00004030static MaybeObject* Runtime_GetInterceptorInfo(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004031 HandleScope scope;
4032 ASSERT(args.length() == 1);
4033 if (!args[0]->IsJSObject()) {
4034 return Smi::FromInt(0);
4035 }
4036 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4037
4038 int result = 0;
4039 if (obj->HasNamedInterceptor()) result |= 2;
4040 if (obj->HasIndexedInterceptor()) result |= 1;
4041
4042 return Smi::FromInt(result);
4043}
4044
4045
4046// Return property names from named interceptor.
4047// args[0]: object
lrn@chromium.org303ada72010-10-27 09:33:13 +00004048static MaybeObject* Runtime_GetNamedInterceptorPropertyNames(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004049 HandleScope scope;
4050 ASSERT(args.length() == 1);
4051 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4052
4053 if (obj->HasNamedInterceptor()) {
4054 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
4055 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4056 }
4057 return Heap::undefined_value();
4058}
4059
4060
4061// Return element names from indexed interceptor.
4062// args[0]: object
lrn@chromium.org303ada72010-10-27 09:33:13 +00004063static MaybeObject* Runtime_GetIndexedInterceptorElementNames(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004064 HandleScope scope;
4065 ASSERT(args.length() == 1);
4066 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4067
4068 if (obj->HasIndexedInterceptor()) {
4069 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
4070 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4071 }
4072 return Heap::undefined_value();
4073}
4074
4075
lrn@chromium.org303ada72010-10-27 09:33:13 +00004076static MaybeObject* Runtime_LocalKeys(Arguments args) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004077 ASSERT_EQ(args.length(), 1);
4078 CONVERT_CHECKED(JSObject, raw_object, args[0]);
4079 HandleScope scope;
4080 Handle<JSObject> object(raw_object);
4081 Handle<FixedArray> contents = GetKeysInFixedArrayFor(object,
4082 LOCAL_ONLY);
4083 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
4084 // property array and since the result is mutable we have to create
4085 // a fresh clone on each invocation.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004086 int length = contents->length();
4087 Handle<FixedArray> copy = Factory::NewFixedArray(length);
4088 for (int i = 0; i < length; i++) {
4089 Object* entry = contents->get(i);
4090 if (entry->IsString()) {
4091 copy->set(i, entry);
4092 } else {
4093 ASSERT(entry->IsNumber());
4094 HandleScope scope;
4095 Handle<Object> entry_handle(entry);
4096 Handle<Object> entry_str = Factory::NumberToString(entry_handle);
4097 copy->set(i, *entry_str);
4098 }
4099 }
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004100 return *Factory::NewJSArrayWithElements(copy);
4101}
4102
4103
lrn@chromium.org303ada72010-10-27 09:33:13 +00004104static MaybeObject* Runtime_GetArgumentsProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004105 NoHandleAllocation ha;
4106 ASSERT(args.length() == 1);
4107
4108 // Compute the frame holding the arguments.
4109 JavaScriptFrameIterator it;
4110 it.AdvanceToArgumentsFrame();
4111 JavaScriptFrame* frame = it.frame();
4112
4113 // Get the actual number of provided arguments.
4114 const uint32_t n = frame->GetProvidedParametersCount();
4115
4116 // Try to convert the key to an index. If successful and within
4117 // index return the the argument from the frame.
4118 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004119 if (args[0]->ToArrayIndex(&index) && index < n) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004120 return frame->GetParameter(index);
4121 }
4122
4123 // Convert the key to a string.
4124 HandleScope scope;
4125 bool exception = false;
4126 Handle<Object> converted =
4127 Execution::ToString(args.at<Object>(0), &exception);
4128 if (exception) return Failure::Exception();
4129 Handle<String> key = Handle<String>::cast(converted);
4130
4131 // Try to convert the string key into an array index.
4132 if (key->AsArrayIndex(&index)) {
4133 if (index < n) {
4134 return frame->GetParameter(index);
4135 } else {
4136 return Top::initial_object_prototype()->GetElement(index);
4137 }
4138 }
4139
4140 // Handle special arguments properties.
4141 if (key->Equals(Heap::length_symbol())) return Smi::FromInt(n);
4142 if (key->Equals(Heap::callee_symbol())) return frame->function();
4143
4144 // Lookup in the initial Object.prototype object.
4145 return Top::initial_object_prototype()->GetProperty(*key);
4146}
4147
4148
lrn@chromium.org303ada72010-10-27 09:33:13 +00004149static MaybeObject* Runtime_ToFastProperties(Arguments args) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004150 HandleScope scope;
4151
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004152 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004153 Handle<Object> object = args.at<Object>(0);
4154 if (object->IsJSObject()) {
4155 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
ager@chromium.org5c838252010-02-19 08:53:10 +00004156 if (!js_object->HasFastProperties() && !js_object->IsGlobalObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004157 MaybeObject* ok = js_object->TransformToFastProperties(0);
4158 if (ok->IsRetryAfterGC()) return ok;
ager@chromium.org5c838252010-02-19 08:53:10 +00004159 }
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004160 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004161 return *object;
4162}
4163
4164
lrn@chromium.org303ada72010-10-27 09:33:13 +00004165static MaybeObject* Runtime_ToSlowProperties(Arguments args) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004166 HandleScope scope;
4167
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004168 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004169 Handle<Object> object = args.at<Object>(0);
4170 if (object->IsJSObject()) {
4171 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004172 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004173 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004174 return *object;
4175}
4176
4177
lrn@chromium.org303ada72010-10-27 09:33:13 +00004178static MaybeObject* Runtime_ToBool(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004179 NoHandleAllocation ha;
4180 ASSERT(args.length() == 1);
4181
4182 return args[0]->ToBoolean();
4183}
4184
4185
4186// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
4187// Possible optimizations: put the type string into the oddballs.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004188static MaybeObject* Runtime_Typeof(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004189 NoHandleAllocation ha;
4190
4191 Object* obj = args[0];
4192 if (obj->IsNumber()) return Heap::number_symbol();
4193 HeapObject* heap_obj = HeapObject::cast(obj);
4194
4195 // typeof an undetectable object is 'undefined'
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004196 if (heap_obj->map()->is_undetectable()) return Heap::undefined_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004197
4198 InstanceType instance_type = heap_obj->map()->instance_type();
4199 if (instance_type < FIRST_NONSTRING_TYPE) {
4200 return Heap::string_symbol();
4201 }
4202
4203 switch (instance_type) {
4204 case ODDBALL_TYPE:
4205 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
4206 return Heap::boolean_symbol();
4207 }
4208 if (heap_obj->IsNull()) {
4209 return Heap::object_symbol();
4210 }
4211 ASSERT(heap_obj->IsUndefined());
4212 return Heap::undefined_symbol();
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00004213 case JS_FUNCTION_TYPE: case JS_REGEXP_TYPE:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004214 return Heap::function_symbol();
4215 default:
4216 // For any kind of object not handled above, the spec rule for
4217 // host objects gives that it is okay to return "object"
4218 return Heap::object_symbol();
4219 }
4220}
4221
4222
lrn@chromium.org25156de2010-04-06 13:10:27 +00004223static bool AreDigits(const char*s, int from, int to) {
4224 for (int i = from; i < to; i++) {
4225 if (s[i] < '0' || s[i] > '9') return false;
4226 }
4227
4228 return true;
4229}
4230
4231
4232static int ParseDecimalInteger(const char*s, int from, int to) {
4233 ASSERT(to - from < 10); // Overflow is not possible.
4234 ASSERT(from < to);
4235 int d = s[from] - '0';
4236
4237 for (int i = from + 1; i < to; i++) {
4238 d = 10 * d + (s[i] - '0');
4239 }
4240
4241 return d;
4242}
4243
4244
lrn@chromium.org303ada72010-10-27 09:33:13 +00004245static MaybeObject* Runtime_StringToNumber(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004246 NoHandleAllocation ha;
4247 ASSERT(args.length() == 1);
4248 CONVERT_CHECKED(String, subject, args[0]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004249 subject->TryFlatten();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004250
4251 // Fast case: short integer or some sorts of junk values.
4252 int len = subject->length();
4253 if (subject->IsSeqAsciiString()) {
4254 if (len == 0) return Smi::FromInt(0);
4255
4256 char const* data = SeqAsciiString::cast(subject)->GetChars();
4257 bool minus = (data[0] == '-');
4258 int start_pos = (minus ? 1 : 0);
4259
4260 if (start_pos == len) {
4261 return Heap::nan_value();
4262 } else if (data[start_pos] > '9') {
4263 // Fast check for a junk value. A valid string may start from a
4264 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
4265 // the 'I' character ('Infinity'). All of that have codes not greater than
4266 // '9' except 'I'.
4267 if (data[start_pos] != 'I') {
4268 return Heap::nan_value();
4269 }
4270 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
4271 // The maximal/minimal smi has 10 digits. If the string has less digits we
4272 // know it will fit into the smi-data type.
4273 int d = ParseDecimalInteger(data, start_pos, len);
4274 if (minus) {
4275 if (d == 0) return Heap::minus_zero_value();
4276 d = -d;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004277 } else if (!subject->HasHashCode() &&
4278 len <= String::kMaxArrayIndexSize &&
4279 (len == 1 || data[0] != '0')) {
4280 // String hash is not calculated yet but all the data are present.
4281 // Update the hash field to speed up sequential convertions.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00004282 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004283#ifdef DEBUG
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004284 subject->Hash(); // Force hash calculation.
4285 ASSERT_EQ(static_cast<int>(subject->hash_field()),
4286 static_cast<int>(hash));
4287#endif
4288 subject->set_hash_field(hash);
lrn@chromium.org25156de2010-04-06 13:10:27 +00004289 }
4290 return Smi::FromInt(d);
4291 }
4292 }
4293
4294 // Slower case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004295 return Heap::NumberFromDouble(StringToDouble(subject, ALLOW_HEX));
4296}
4297
4298
lrn@chromium.org303ada72010-10-27 09:33:13 +00004299static MaybeObject* Runtime_StringFromCharCodeArray(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004300 NoHandleAllocation ha;
4301 ASSERT(args.length() == 1);
4302
4303 CONVERT_CHECKED(JSArray, codes, args[0]);
4304 int length = Smi::cast(codes->length())->value();
4305
4306 // Check if the string can be ASCII.
4307 int i;
4308 for (i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004309 Object* element;
4310 { MaybeObject* maybe_element = codes->GetElement(i);
4311 // We probably can't get an exception here, but just in order to enforce
4312 // the checking of inputs in the runtime calls we check here.
4313 if (!maybe_element->ToObject(&element)) return maybe_element;
4314 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004315 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
4316 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
4317 break;
4318 }
4319
lrn@chromium.org303ada72010-10-27 09:33:13 +00004320 MaybeObject* maybe_object = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004321 if (i == length) { // The string is ASCII.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004322 maybe_object = Heap::AllocateRawAsciiString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004323 } else { // The string is not ASCII.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004324 maybe_object = Heap::AllocateRawTwoByteString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004325 }
4326
lrn@chromium.org303ada72010-10-27 09:33:13 +00004327 Object* object = NULL;
4328 if (!maybe_object->ToObject(&object)) return maybe_object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004329 String* result = String::cast(object);
4330 for (int i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004331 Object* element;
4332 { MaybeObject* maybe_element = codes->GetElement(i);
4333 if (!maybe_element->ToObject(&element)) return maybe_element;
4334 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004335 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004336 result->Set(i, chr & 0xffff);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004337 }
4338 return result;
4339}
4340
4341
4342// kNotEscaped is generated by the following:
4343//
4344// #!/bin/perl
4345// for (my $i = 0; $i < 256; $i++) {
4346// print "\n" if $i % 16 == 0;
4347// my $c = chr($i);
4348// my $escaped = 1;
4349// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
4350// print $escaped ? "0, " : "1, ";
4351// }
4352
4353
4354static bool IsNotEscaped(uint16_t character) {
4355 // Only for 8 bit characters, the rest are always escaped (in a different way)
4356 ASSERT(character < 256);
4357 static const char kNotEscaped[256] = {
4358 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4359 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4360 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
4361 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
4362 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4363 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
4364 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4365 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
4366 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4367 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4368 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4369 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4370 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4371 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4372 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4373 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4374 };
4375 return kNotEscaped[character] != 0;
4376}
4377
4378
lrn@chromium.org303ada72010-10-27 09:33:13 +00004379static MaybeObject* Runtime_URIEscape(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004380 const char hex_chars[] = "0123456789ABCDEF";
4381 NoHandleAllocation ha;
4382 ASSERT(args.length() == 1);
4383 CONVERT_CHECKED(String, source, args[0]);
4384
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004385 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004386
4387 int escaped_length = 0;
4388 int length = source->length();
4389 {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004390 Access<StringInputBuffer> buffer(&runtime_string_input_buffer);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004391 buffer->Reset(source);
4392 while (buffer->has_more()) {
4393 uint16_t character = buffer->GetNext();
4394 if (character >= 256) {
4395 escaped_length += 6;
4396 } else if (IsNotEscaped(character)) {
4397 escaped_length++;
4398 } else {
4399 escaped_length += 3;
4400 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004401 // We don't allow strings that are longer than a maximal length.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004402 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004403 if (escaped_length > String::kMaxLength) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004404 Top::context()->mark_out_of_memory();
4405 return Failure::OutOfMemoryException();
4406 }
4407 }
4408 }
4409 // No length change implies no change. Return original string if no change.
4410 if (escaped_length == length) {
4411 return source;
4412 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00004413 Object* o;
4414 { MaybeObject* maybe_o = Heap::AllocateRawAsciiString(escaped_length);
4415 if (!maybe_o->ToObject(&o)) return maybe_o;
4416 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004417 String* destination = String::cast(o);
4418 int dest_position = 0;
4419
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004420 Access<StringInputBuffer> buffer(&runtime_string_input_buffer);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004421 buffer->Rewind();
4422 while (buffer->has_more()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00004423 uint16_t chr = buffer->GetNext();
4424 if (chr >= 256) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004425 destination->Set(dest_position, '%');
4426 destination->Set(dest_position+1, 'u');
4427 destination->Set(dest_position+2, hex_chars[chr >> 12]);
4428 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]);
4429 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]);
4430 destination->Set(dest_position+5, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004431 dest_position += 6;
ager@chromium.org870a0b62008-11-04 11:43:05 +00004432 } else if (IsNotEscaped(chr)) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004433 destination->Set(dest_position, chr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004434 dest_position++;
4435 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004436 destination->Set(dest_position, '%');
4437 destination->Set(dest_position+1, hex_chars[chr >> 4]);
4438 destination->Set(dest_position+2, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004439 dest_position += 3;
4440 }
4441 }
4442 return destination;
4443}
4444
4445
4446static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
4447 static const signed char kHexValue['g'] = {
4448 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4449 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4450 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4451 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
4452 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4453 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4454 -1, 10, 11, 12, 13, 14, 15 };
4455
4456 if (character1 > 'f') return -1;
4457 int hi = kHexValue[character1];
4458 if (hi == -1) return -1;
4459 if (character2 > 'f') return -1;
4460 int lo = kHexValue[character2];
4461 if (lo == -1) return -1;
4462 return (hi << 4) + lo;
4463}
4464
4465
ager@chromium.org870a0b62008-11-04 11:43:05 +00004466static inline int Unescape(String* source,
ager@chromium.org870a0b62008-11-04 11:43:05 +00004467 int i,
4468 int length,
4469 int* step) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004470 uint16_t character = source->Get(i);
ager@chromium.org870a0b62008-11-04 11:43:05 +00004471 int32_t hi = 0;
4472 int32_t lo = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004473 if (character == '%' &&
4474 i <= length - 6 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004475 source->Get(i + 1) == 'u' &&
4476 (hi = TwoDigitHex(source->Get(i + 2),
4477 source->Get(i + 3))) != -1 &&
4478 (lo = TwoDigitHex(source->Get(i + 4),
4479 source->Get(i + 5))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004480 *step = 6;
4481 return (hi << 8) + lo;
4482 } else if (character == '%' &&
4483 i <= length - 3 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004484 (lo = TwoDigitHex(source->Get(i + 1),
4485 source->Get(i + 2))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004486 *step = 3;
4487 return lo;
4488 } else {
4489 *step = 1;
4490 return character;
4491 }
4492}
4493
4494
lrn@chromium.org303ada72010-10-27 09:33:13 +00004495static MaybeObject* Runtime_URIUnescape(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004496 NoHandleAllocation ha;
4497 ASSERT(args.length() == 1);
4498 CONVERT_CHECKED(String, source, args[0]);
4499
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004500 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004501
4502 bool ascii = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004503 int length = source->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004504
4505 int unescaped_length = 0;
4506 for (int i = 0; i < length; unescaped_length++) {
4507 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004508 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004509 ascii = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004510 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004511 i += step;
4512 }
4513
4514 // No length change implies no change. Return original string if no change.
4515 if (unescaped_length == length)
4516 return source;
4517
lrn@chromium.org303ada72010-10-27 09:33:13 +00004518 Object* o;
4519 { MaybeObject* maybe_o = ascii ?
4520 Heap::AllocateRawAsciiString(unescaped_length) :
4521 Heap::AllocateRawTwoByteString(unescaped_length);
4522 if (!maybe_o->ToObject(&o)) return maybe_o;
4523 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004524 String* destination = String::cast(o);
4525
4526 int dest_position = 0;
4527 for (int i = 0; i < length; dest_position++) {
4528 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004529 destination->Set(dest_position, Unescape(source, i, length, &step));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004530 i += step;
4531 }
4532 return destination;
4533}
4534
4535
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004536static const unsigned int kQuoteTableLength = 128u;
4537
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004538static const int kJsonQuotesCharactersPerEntry = 8;
4539static const char* const JsonQuotes =
4540 "\\u0000 \\u0001 \\u0002 \\u0003 "
4541 "\\u0004 \\u0005 \\u0006 \\u0007 "
4542 "\\b \\t \\n \\u000b "
4543 "\\f \\r \\u000e \\u000f "
4544 "\\u0010 \\u0011 \\u0012 \\u0013 "
4545 "\\u0014 \\u0015 \\u0016 \\u0017 "
4546 "\\u0018 \\u0019 \\u001a \\u001b "
4547 "\\u001c \\u001d \\u001e \\u001f "
4548 " ! \\\" # "
4549 "$ % & ' "
4550 "( ) * + "
4551 ", - . / "
4552 "0 1 2 3 "
4553 "4 5 6 7 "
4554 "8 9 : ; "
4555 "< = > ? "
4556 "@ A B C "
4557 "D E F G "
4558 "H I J K "
4559 "L M N O "
4560 "P Q R S "
4561 "T U V W "
4562 "X Y Z [ "
4563 "\\\\ ] ^ _ "
4564 "` a b c "
4565 "d e f g "
4566 "h i j k "
4567 "l m n o "
4568 "p q r s "
4569 "t u v w "
4570 "x y z { "
4571 "| } ~ \177 ";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004572
4573
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004574// For a string that is less than 32k characters it should always be
4575// possible to allocate it in new space.
4576static const int kMaxGuaranteedNewSpaceString = 32 * 1024;
4577
4578
4579// Doing JSON quoting cannot make the string more than this many times larger.
4580static const int kJsonQuoteWorstCaseBlowup = 6;
4581
4582
4583// Covers the entire ASCII range (all other characters are unchanged by JSON
4584// quoting).
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004585static const byte JsonQuoteLengths[kQuoteTableLength] = {
4586 6, 6, 6, 6, 6, 6, 6, 6,
4587 2, 2, 2, 6, 2, 2, 6, 6,
4588 6, 6, 6, 6, 6, 6, 6, 6,
4589 6, 6, 6, 6, 6, 6, 6, 6,
4590 1, 1, 2, 1, 1, 1, 1, 1,
4591 1, 1, 1, 1, 1, 1, 1, 1,
4592 1, 1, 1, 1, 1, 1, 1, 1,
4593 1, 1, 1, 1, 1, 1, 1, 1,
4594 1, 1, 1, 1, 1, 1, 1, 1,
4595 1, 1, 1, 1, 1, 1, 1, 1,
4596 1, 1, 1, 1, 1, 1, 1, 1,
4597 1, 1, 1, 1, 2, 1, 1, 1,
4598 1, 1, 1, 1, 1, 1, 1, 1,
4599 1, 1, 1, 1, 1, 1, 1, 1,
4600 1, 1, 1, 1, 1, 1, 1, 1,
4601 1, 1, 1, 1, 1, 1, 1, 1,
4602};
4603
4604
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004605template <typename StringType>
4606MaybeObject* AllocateRawString(int length);
4607
4608
4609template <>
4610MaybeObject* AllocateRawString<SeqTwoByteString>(int length) {
4611 return Heap::AllocateRawTwoByteString(length);
4612}
4613
4614
4615template <>
4616MaybeObject* AllocateRawString<SeqAsciiString>(int length) {
4617 return Heap::AllocateRawAsciiString(length);
4618}
4619
4620
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004621template <typename Char, typename StringType, bool comma>
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004622static MaybeObject* SlowQuoteJsonString(Vector<const Char> characters) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004623 int length = characters.length();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004624 const Char* read_cursor = characters.start();
4625 const Char* end = read_cursor + length;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004626 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004627 int quoted_length = kSpaceForQuotes;
4628 while (read_cursor < end) {
4629 Char c = *(read_cursor++);
4630 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
4631 quoted_length++;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004632 } else {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004633 quoted_length += JsonQuoteLengths[static_cast<unsigned>(c)];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004634 }
4635 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004636 MaybeObject* new_alloc = AllocateRawString<StringType>(quoted_length);
4637 Object* new_object;
4638 if (!new_alloc->ToObject(&new_object)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004639 return new_alloc;
4640 }
4641 StringType* new_string = StringType::cast(new_object);
4642
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004643 Char* write_cursor = reinterpret_cast<Char*>(
4644 new_string->address() + SeqAsciiString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004645 if (comma) *(write_cursor++) = ',';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004646 *(write_cursor++) = '"';
4647
4648 read_cursor = characters.start();
4649 while (read_cursor < end) {
4650 Char c = *(read_cursor++);
4651 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
4652 *(write_cursor++) = c;
4653 } else {
4654 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
4655 const char* replacement = JsonQuotes +
4656 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
4657 for (int i = 0; i < len; i++) {
4658 *write_cursor++ = *replacement++;
4659 }
4660 }
4661 }
4662 *(write_cursor++) = '"';
4663 return new_string;
4664}
4665
4666
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004667template <typename Char, typename StringType, bool comma>
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004668static MaybeObject* QuoteJsonString(Vector<const Char> characters) {
4669 int length = characters.length();
4670 Counters::quote_json_char_count.Increment(length);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004671 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004672 int worst_case_length = length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotes;
4673 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004674 return SlowQuoteJsonString<Char, StringType, comma>(characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004675 }
4676
4677 MaybeObject* new_alloc = AllocateRawString<StringType>(worst_case_length);
4678 Object* new_object;
4679 if (!new_alloc->ToObject(&new_object)) {
4680 return new_alloc;
4681 }
4682 if (!Heap::new_space()->Contains(new_object)) {
4683 // Even if our string is small enough to fit in new space we still have to
4684 // handle it being allocated in old space as may happen in the third
4685 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
4686 // CEntryStub::GenerateCore.
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004687 return SlowQuoteJsonString<Char, StringType, comma>(characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004688 }
4689 StringType* new_string = StringType::cast(new_object);
4690 ASSERT(Heap::new_space()->Contains(new_string));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004691
4692 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize);
4693 Char* write_cursor = reinterpret_cast<Char*>(
4694 new_string->address() + SeqAsciiString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004695 if (comma) *(write_cursor++) = ',';
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004696 *(write_cursor++) = '"';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004697
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004698 const Char* read_cursor = characters.start();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004699 const Char* end = read_cursor + length;
4700 while (read_cursor < end) {
4701 Char c = *(read_cursor++);
4702 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
4703 *(write_cursor++) = c;
4704 } else {
4705 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
4706 const char* replacement = JsonQuotes +
4707 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
4708 write_cursor[0] = replacement[0];
4709 if (len > 1) {
4710 write_cursor[1] = replacement[1];
4711 if (len > 2) {
4712 ASSERT(len == 6);
4713 write_cursor[2] = replacement[2];
4714 write_cursor[3] = replacement[3];
4715 write_cursor[4] = replacement[4];
4716 write_cursor[5] = replacement[5];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004717 }
4718 }
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004719 write_cursor += len;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004720 }
4721 }
4722 *(write_cursor++) = '"';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004723
4724 int final_length = static_cast<int>(
4725 write_cursor - reinterpret_cast<Char*>(
4726 new_string->address() + SeqAsciiString::kHeaderSize));
4727 Heap::new_space()->ShrinkStringAtAllocationBoundary<StringType>(new_string,
4728 final_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004729 return new_string;
4730}
4731
4732
4733static MaybeObject* Runtime_QuoteJSONString(Arguments args) {
4734 NoHandleAllocation ha;
4735 CONVERT_CHECKED(String, str, args[0]);
4736 if (!str->IsFlat()) {
4737 MaybeObject* try_flatten = str->TryFlatten();
4738 Object* flat;
4739 if (!try_flatten->ToObject(&flat)) {
4740 return try_flatten;
4741 }
4742 str = String::cast(flat);
4743 ASSERT(str->IsFlat());
4744 }
4745 if (str->IsTwoByteRepresentation()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004746 return QuoteJsonString<uc16, SeqTwoByteString, false>(str->ToUC16Vector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004747 } else {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004748 return QuoteJsonString<char, SeqAsciiString, false>(str->ToAsciiVector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004749 }
4750}
4751
4752
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004753static MaybeObject* Runtime_QuoteJSONStringComma(Arguments args) {
4754 NoHandleAllocation ha;
4755 CONVERT_CHECKED(String, str, args[0]);
4756 if (!str->IsFlat()) {
4757 MaybeObject* try_flatten = str->TryFlatten();
4758 Object* flat;
4759 if (!try_flatten->ToObject(&flat)) {
4760 return try_flatten;
4761 }
4762 str = String::cast(flat);
4763 ASSERT(str->IsFlat());
4764 }
4765 if (str->IsTwoByteRepresentation()) {
4766 return QuoteJsonString<uc16, SeqTwoByteString, true>(str->ToUC16Vector());
4767 } else {
4768 return QuoteJsonString<char, SeqAsciiString, true>(str->ToAsciiVector());
4769 }
4770}
4771
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004772
lrn@chromium.org303ada72010-10-27 09:33:13 +00004773static MaybeObject* Runtime_StringParseInt(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004774 NoHandleAllocation ha;
4775
4776 CONVERT_CHECKED(String, s, args[0]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00004777 CONVERT_SMI_CHECKED(radix, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004778
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004779 s->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004780
lrn@chromium.org25156de2010-04-06 13:10:27 +00004781 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
4782 double value = StringToInt(s, radix);
4783 return Heap::NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004784}
4785
4786
lrn@chromium.org303ada72010-10-27 09:33:13 +00004787static MaybeObject* Runtime_StringParseFloat(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004788 NoHandleAllocation ha;
4789 CONVERT_CHECKED(String, str, args[0]);
4790
4791 // ECMA-262 section 15.1.2.3, empty string is NaN
4792 double value = StringToDouble(str, ALLOW_TRAILING_JUNK, OS::nan_value());
4793
4794 // Create a number object from the value.
4795 return Heap::NumberFromDouble(value);
4796}
4797
4798
4799static unibrow::Mapping<unibrow::ToUppercase, 128> to_upper_mapping;
4800static unibrow::Mapping<unibrow::ToLowercase, 128> to_lower_mapping;
4801
4802
4803template <class Converter>
lrn@chromium.org303ada72010-10-27 09:33:13 +00004804MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
4805 String* s,
4806 int length,
4807 int input_string_length,
4808 unibrow::Mapping<Converter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004809 // We try this twice, once with the assumption that the result is no longer
4810 // than the input and, if that assumption breaks, again with the exact
4811 // length. This may not be pretty, but it is nicer than what was here before
4812 // and I hereby claim my vaffel-is.
4813 //
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004814 // Allocate the resulting string.
4815 //
4816 // NOTE: This assumes that the upper/lower case of an ascii
4817 // character is also ascii. This is currently the case, but it
4818 // might break in the future if we implement more context and locale
4819 // dependent upper/lower conversions.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004820 Object* o;
4821 { MaybeObject* maybe_o = s->IsAsciiRepresentation()
4822 ? Heap::AllocateRawAsciiString(length)
4823 : Heap::AllocateRawTwoByteString(length);
4824 if (!maybe_o->ToObject(&o)) return maybe_o;
4825 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004826 String* result = String::cast(o);
4827 bool has_changed_character = false;
4828
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004829 // Convert all characters to upper case, assuming that they will fit
4830 // in the buffer
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004831 Access<StringInputBuffer> buffer(&runtime_string_input_buffer);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004832 buffer->Reset(s);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004833 unibrow::uchar chars[Converter::kMaxWidth];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004834 // We can assume that the string is not empty
4835 uc32 current = buffer->GetNext();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004836 for (int i = 0; i < length;) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00004837 bool has_next = buffer->has_more();
4838 uc32 next = has_next ? buffer->GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004839 int char_length = mapping->get(current, next, chars);
4840 if (char_length == 0) {
4841 // The case conversion of this character is the character itself.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004842 result->Set(i, current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004843 i++;
4844 } else if (char_length == 1) {
4845 // Common case: converting the letter resulted in one character.
4846 ASSERT(static_cast<uc32>(chars[0]) != current);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004847 result->Set(i, chars[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004848 has_changed_character = true;
4849 i++;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004850 } else if (length == input_string_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004851 // We've assumed that the result would be as long as the
4852 // input but here is a character that converts to several
4853 // characters. No matter, we calculate the exact length
4854 // of the result and try the whole thing again.
4855 //
4856 // Note that this leaves room for optimization. We could just
4857 // memcpy what we already have to the result string. Also,
4858 // the result string is the last object allocated we could
4859 // "realloc" it and probably, in the vast majority of cases,
4860 // extend the existing string to be able to hold the full
4861 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00004862 int next_length = 0;
4863 if (has_next) {
4864 next_length = mapping->get(next, 0, chars);
4865 if (next_length == 0) next_length = 1;
4866 }
4867 int current_length = i + char_length + next_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004868 while (buffer->has_more()) {
4869 current = buffer->GetNext();
ager@chromium.org7c537e22008-10-16 08:43:32 +00004870 // NOTE: we use 0 as the next character here because, while
4871 // the next character may affect what a character converts to,
4872 // it does not in any case affect the length of what it convert
4873 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004874 int char_length = mapping->get(current, 0, chars);
4875 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00004876 current_length += char_length;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004877 if (current_length > Smi::kMaxValue) {
4878 Top::context()->mark_out_of_memory();
4879 return Failure::OutOfMemoryException();
4880 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004881 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004882 // Try again with the real length.
4883 return Smi::FromInt(current_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004884 } else {
4885 for (int j = 0; j < char_length; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004886 result->Set(i, chars[j]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004887 i++;
4888 }
4889 has_changed_character = true;
4890 }
4891 current = next;
4892 }
4893 if (has_changed_character) {
4894 return result;
4895 } else {
4896 // If we didn't actually change anything in doing the conversion
4897 // we simple return the result and let the converted string
4898 // become garbage; there is no reason to keep two identical strings
4899 // alive.
4900 return s;
4901 }
4902}
4903
4904
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004905namespace {
4906
lrn@chromium.org303ada72010-10-27 09:33:13 +00004907static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF;
4908
4909
4910// Given a word and two range boundaries returns a word with high bit
4911// set in every byte iff the corresponding input byte was strictly in
4912// the range (m, n). All the other bits in the result are cleared.
4913// This function is only useful when it can be inlined and the
4914// boundaries are statically known.
4915// Requires: all bytes in the input word and the boundaries must be
4916// ascii (less than 0x7F).
4917static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
4918 // Every byte in an ascii string is less than or equal to 0x7F.
4919 ASSERT((w & (kOneInEveryByte * 0x7F)) == w);
4920 // Use strict inequalities since in edge cases the function could be
4921 // further simplified.
4922 ASSERT(0 < m && m < n && n < 0x7F);
4923 // Has high bit set in every w byte less than n.
4924 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w;
4925 // Has high bit set in every w byte greater than m.
4926 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m);
4927 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80));
4928}
4929
4930
4931enum AsciiCaseConversion {
4932 ASCII_TO_LOWER,
4933 ASCII_TO_UPPER
4934};
4935
4936
4937template <AsciiCaseConversion dir>
4938struct FastAsciiConverter {
4939 static bool Convert(char* dst, char* src, int length) {
4940#ifdef DEBUG
4941 char* saved_dst = dst;
4942 char* saved_src = src;
4943#endif
4944 // We rely on the distance between upper and lower case letters
4945 // being a known power of 2.
4946 ASSERT('a' - 'A' == (1 << 5));
4947 // Boundaries for the range of input characters than require conversion.
4948 const char lo = (dir == ASCII_TO_LOWER) ? 'A' - 1 : 'a' - 1;
4949 const char hi = (dir == ASCII_TO_LOWER) ? 'Z' + 1 : 'z' + 1;
4950 bool changed = false;
4951 char* const limit = src + length;
4952#ifdef V8_HOST_CAN_READ_UNALIGNED
4953 // Process the prefix of the input that requires no conversion one
4954 // (machine) word at a time.
4955 while (src <= limit - sizeof(uintptr_t)) {
4956 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
4957 if (AsciiRangeMask(w, lo, hi) != 0) {
4958 changed = true;
4959 break;
4960 }
4961 *reinterpret_cast<uintptr_t*>(dst) = w;
4962 src += sizeof(uintptr_t);
4963 dst += sizeof(uintptr_t);
4964 }
4965 // Process the remainder of the input performing conversion when
4966 // required one word at a time.
4967 while (src <= limit - sizeof(uintptr_t)) {
4968 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
4969 uintptr_t m = AsciiRangeMask(w, lo, hi);
4970 // The mask has high (7th) bit set in every byte that needs
4971 // conversion and we know that the distance between cases is
4972 // 1 << 5.
4973 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
4974 src += sizeof(uintptr_t);
4975 dst += sizeof(uintptr_t);
4976 }
4977#endif
4978 // Process the last few bytes of the input (or the whole input if
4979 // unaligned access is not supported).
4980 while (src < limit) {
4981 char c = *src;
4982 if (lo < c && c < hi) {
4983 c ^= (1 << 5);
4984 changed = true;
4985 }
4986 *dst = c;
4987 ++src;
4988 ++dst;
4989 }
4990#ifdef DEBUG
4991 CheckConvert(saved_dst, saved_src, length, changed);
4992#endif
4993 return changed;
4994 }
4995
4996#ifdef DEBUG
4997 static void CheckConvert(char* dst, char* src, int length, bool changed) {
4998 bool expected_changed = false;
4999 for (int i = 0; i < length; i++) {
5000 if (dst[i] == src[i]) continue;
5001 expected_changed = true;
5002 if (dir == ASCII_TO_LOWER) {
5003 ASSERT('A' <= src[i] && src[i] <= 'Z');
5004 ASSERT(dst[i] == src[i] + ('a' - 'A'));
5005 } else {
5006 ASSERT(dir == ASCII_TO_UPPER);
5007 ASSERT('a' <= src[i] && src[i] <= 'z');
5008 ASSERT(dst[i] == src[i] - ('a' - 'A'));
5009 }
5010 }
5011 ASSERT(expected_changed == changed);
5012 }
5013#endif
5014};
5015
5016
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005017struct ToLowerTraits {
5018 typedef unibrow::ToLowercase UnibrowConverter;
5019
lrn@chromium.org303ada72010-10-27 09:33:13 +00005020 typedef FastAsciiConverter<ASCII_TO_LOWER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005021};
5022
5023
5024struct ToUpperTraits {
5025 typedef unibrow::ToUppercase UnibrowConverter;
5026
lrn@chromium.org303ada72010-10-27 09:33:13 +00005027 typedef FastAsciiConverter<ASCII_TO_UPPER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005028};
5029
5030} // namespace
5031
5032
5033template <typename ConvertTraits>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005034MUST_USE_RESULT static MaybeObject* ConvertCase(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005035 Arguments args,
5036 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005037 NoHandleAllocation ha;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005038 CONVERT_CHECKED(String, s, args[0]);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005039 s = s->TryFlattenGetString();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005040
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005041 const int length = s->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005042 // Assume that the string is not empty; we need this assumption later
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005043 if (length == 0) return s;
5044
5045 // Simpler handling of ascii strings.
5046 //
5047 // NOTE: This assumes that the upper/lower case of an ascii
5048 // character is also ascii. This is currently the case, but it
5049 // might break in the future if we implement more context and locale
5050 // dependent upper/lower conversions.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005051 if (s->IsSeqAsciiString()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005052 Object* o;
5053 { MaybeObject* maybe_o = Heap::AllocateRawAsciiString(length);
5054 if (!maybe_o->ToObject(&o)) return maybe_o;
5055 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005056 SeqAsciiString* result = SeqAsciiString::cast(o);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005057 bool has_changed_character = ConvertTraits::AsciiConverter::Convert(
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005058 result->GetChars(), SeqAsciiString::cast(s)->GetChars(), length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005059 return has_changed_character ? result : s;
5060 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005061
lrn@chromium.org303ada72010-10-27 09:33:13 +00005062 Object* answer;
5063 { MaybeObject* maybe_answer = ConvertCaseHelper(s, length, length, mapping);
5064 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5065 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005066 if (answer->IsSmi()) {
5067 // Retry with correct length.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005068 { MaybeObject* maybe_answer =
5069 ConvertCaseHelper(s, Smi::cast(answer)->value(), length, mapping);
5070 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5071 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005072 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00005073 return answer;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005074}
5075
5076
lrn@chromium.org303ada72010-10-27 09:33:13 +00005077static MaybeObject* Runtime_StringToLowerCase(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005078 return ConvertCase<ToLowerTraits>(args, &to_lower_mapping);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005079}
5080
5081
lrn@chromium.org303ada72010-10-27 09:33:13 +00005082static MaybeObject* Runtime_StringToUpperCase(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005083 return ConvertCase<ToUpperTraits>(args, &to_upper_mapping);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005084}
5085
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005086
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005087static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
5088 return unibrow::WhiteSpace::Is(c) || c == 0x200b;
5089}
5090
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005091
lrn@chromium.org303ada72010-10-27 09:33:13 +00005092static MaybeObject* Runtime_StringTrim(Arguments args) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005093 NoHandleAllocation ha;
5094 ASSERT(args.length() == 3);
5095
5096 CONVERT_CHECKED(String, s, args[0]);
5097 CONVERT_BOOLEAN_CHECKED(trimLeft, args[1]);
5098 CONVERT_BOOLEAN_CHECKED(trimRight, args[2]);
5099
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005100 s->TryFlatten();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005101 int length = s->length();
5102
5103 int left = 0;
5104 if (trimLeft) {
5105 while (left < length && IsTrimWhiteSpace(s->Get(left))) {
5106 left++;
5107 }
5108 }
5109
5110 int right = length;
5111 if (trimRight) {
5112 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) {
5113 right--;
5114 }
5115 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005116 return s->SubString(left, right);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005117}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005118
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005119
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005120template <typename SubjectChar, typename PatternChar>
5121void FindStringIndices(Vector<const SubjectChar> subject,
5122 Vector<const PatternChar> pattern,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005123 ZoneList<int>* indices,
5124 unsigned int limit) {
5125 ASSERT(limit > 0);
5126 // Collect indices of pattern in subject, and the end-of-string index.
5127 // Stop after finding at most limit values.
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005128 StringSearch<PatternChar, SubjectChar> search(pattern);
5129 int pattern_length = pattern.length();
5130 int index = 0;
5131 while (limit > 0) {
5132 index = search.Search(subject, index);
5133 if (index < 0) return;
5134 indices->Add(index);
5135 index += pattern_length;
5136 limit--;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005137 }
5138}
5139
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005140
lrn@chromium.org303ada72010-10-27 09:33:13 +00005141static MaybeObject* Runtime_StringSplit(Arguments args) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005142 ASSERT(args.length() == 3);
5143 HandleScope handle_scope;
5144 CONVERT_ARG_CHECKED(String, subject, 0);
5145 CONVERT_ARG_CHECKED(String, pattern, 1);
5146 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
5147
5148 int subject_length = subject->length();
5149 int pattern_length = pattern->length();
5150 RUNTIME_ASSERT(pattern_length > 0);
5151
5152 // The limit can be very large (0xffffffffu), but since the pattern
5153 // isn't empty, we can never create more parts than ~half the length
5154 // of the subject.
5155
5156 if (!subject->IsFlat()) FlattenString(subject);
5157
5158 static const int kMaxInitialListCapacity = 16;
5159
5160 ZoneScope scope(DELETE_ON_EXIT);
5161
5162 // Find (up to limit) indices of separator and end-of-string in subject
5163 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
5164 ZoneList<int> indices(initial_capacity);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005165 if (!pattern->IsFlat()) FlattenString(pattern);
5166
5167 // No allocation block.
5168 {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005169 AssertNoAllocation nogc;
5170 if (subject->IsAsciiRepresentation()) {
5171 Vector<const char> subject_vector = subject->ToAsciiVector();
5172 if (pattern->IsAsciiRepresentation()) {
5173 FindStringIndices(subject_vector,
5174 pattern->ToAsciiVector(),
5175 &indices,
5176 limit);
5177 } else {
5178 FindStringIndices(subject_vector,
5179 pattern->ToUC16Vector(),
5180 &indices,
5181 limit);
5182 }
5183 } else {
5184 Vector<const uc16> subject_vector = subject->ToUC16Vector();
5185 if (pattern->IsAsciiRepresentation()) {
5186 FindStringIndices(subject_vector,
5187 pattern->ToAsciiVector(),
5188 &indices,
5189 limit);
5190 } else {
5191 FindStringIndices(subject_vector,
5192 pattern->ToUC16Vector(),
5193 &indices,
5194 limit);
5195 }
5196 }
5197 }
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005198
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005199 if (static_cast<uint32_t>(indices.length()) < limit) {
5200 indices.Add(subject_length);
5201 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005202
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005203 // The list indices now contains the end of each part to create.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005204
5205 // Create JSArray of substrings separated by separator.
5206 int part_count = indices.length();
5207
5208 Handle<JSArray> result = Factory::NewJSArray(part_count);
5209 result->set_length(Smi::FromInt(part_count));
5210
5211 ASSERT(result->HasFastElements());
5212
5213 if (part_count == 1 && indices.at(0) == subject_length) {
5214 FixedArray::cast(result->elements())->set(0, *subject);
5215 return *result;
5216 }
5217
5218 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
5219 int part_start = 0;
5220 for (int i = 0; i < part_count; i++) {
5221 HandleScope local_loop_handle;
5222 int part_end = indices.at(i);
5223 Handle<String> substring =
5224 Factory::NewSubString(subject, part_start, part_end);
5225 elements->set(i, *substring);
5226 part_start = part_end + pattern_length;
5227 }
5228
5229 return *result;
5230}
5231
5232
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005233// Copies ascii characters to the given fixed array looking up
5234// one-char strings in the cache. Gives up on the first char that is
5235// not in the cache and fills the remainder with smi zeros. Returns
5236// the length of the successfully copied prefix.
5237static int CopyCachedAsciiCharsToArray(const char* chars,
5238 FixedArray* elements,
5239 int length) {
5240 AssertNoAllocation nogc;
5241 FixedArray* ascii_cache = Heap::single_character_string_cache();
5242 Object* undefined = Heap::undefined_value();
5243 int i;
5244 for (i = 0; i < length; ++i) {
5245 Object* value = ascii_cache->get(chars[i]);
5246 if (value == undefined) break;
5247 ASSERT(!Heap::InNewSpace(value));
5248 elements->set(i, value, SKIP_WRITE_BARRIER);
5249 }
5250 if (i < length) {
5251 ASSERT(Smi::FromInt(0) == 0);
5252 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
5253 }
5254#ifdef DEBUG
5255 for (int j = 0; j < length; ++j) {
5256 Object* element = elements->get(j);
5257 ASSERT(element == Smi::FromInt(0) ||
5258 (element->IsString() && String::cast(element)->LooksValid()));
5259 }
5260#endif
5261 return i;
5262}
5263
5264
5265// Converts a String to JSArray.
5266// For example, "foo" => ["f", "o", "o"].
lrn@chromium.org303ada72010-10-27 09:33:13 +00005267static MaybeObject* Runtime_StringToArray(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005268 HandleScope scope;
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005269 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005270 CONVERT_ARG_CHECKED(String, s, 0);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005271 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005272
5273 s->TryFlatten();
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005274 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005275
5276 Handle<FixedArray> elements;
5277 if (s->IsFlat() && s->IsAsciiRepresentation()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005278 Object* obj;
5279 { MaybeObject* maybe_obj = Heap::AllocateUninitializedFixedArray(length);
5280 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5281 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005282 elements = Handle<FixedArray>(FixedArray::cast(obj));
5283
5284 Vector<const char> chars = s->ToAsciiVector();
5285 // Note, this will initialize all elements (not only the prefix)
5286 // to prevent GC from seeing partially initialized array.
5287 int num_copied_from_cache = CopyCachedAsciiCharsToArray(chars.start(),
5288 *elements,
5289 length);
5290
5291 for (int i = num_copied_from_cache; i < length; ++i) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00005292 Handle<Object> str = LookupSingleCharacterStringFromCode(chars[i]);
5293 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005294 }
5295 } else {
5296 elements = Factory::NewFixedArray(length);
5297 for (int i = 0; i < length; ++i) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00005298 Handle<Object> str = LookupSingleCharacterStringFromCode(s->Get(i));
5299 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005300 }
5301 }
5302
5303#ifdef DEBUG
5304 for (int i = 0; i < length; ++i) {
5305 ASSERT(String::cast(elements->get(i))->length() == 1);
5306 }
5307#endif
5308
5309 return *Factory::NewJSArrayWithElements(elements);
5310}
5311
5312
lrn@chromium.org303ada72010-10-27 09:33:13 +00005313static MaybeObject* Runtime_NewStringWrapper(Arguments args) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005314 NoHandleAllocation ha;
5315 ASSERT(args.length() == 1);
5316 CONVERT_CHECKED(String, value, args[0]);
5317 return value->ToObject();
5318}
5319
5320
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00005321bool Runtime::IsUpperCaseChar(uint16_t ch) {
5322 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
5323 int char_length = to_upper_mapping.get(ch, 0, chars);
5324 return char_length == 0;
5325}
5326
5327
lrn@chromium.org303ada72010-10-27 09:33:13 +00005328static MaybeObject* Runtime_NumberToString(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005329 NoHandleAllocation ha;
5330 ASSERT(args.length() == 1);
5331
5332 Object* number = args[0];
5333 RUNTIME_ASSERT(number->IsNumber());
5334
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005335 return Heap::NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005336}
5337
5338
lrn@chromium.org303ada72010-10-27 09:33:13 +00005339static MaybeObject* Runtime_NumberToStringSkipCache(Arguments args) {
ager@chromium.org357bf652010-04-12 11:30:10 +00005340 NoHandleAllocation ha;
5341 ASSERT(args.length() == 1);
5342
5343 Object* number = args[0];
5344 RUNTIME_ASSERT(number->IsNumber());
5345
5346 return Heap::NumberToString(number, false);
5347}
5348
5349
lrn@chromium.org303ada72010-10-27 09:33:13 +00005350static MaybeObject* Runtime_NumberToInteger(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005351 NoHandleAllocation ha;
5352 ASSERT(args.length() == 1);
5353
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005354 CONVERT_DOUBLE_CHECKED(number, args[0]);
5355
5356 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5357 if (number > 0 && number <= Smi::kMaxValue) {
5358 return Smi::FromInt(static_cast<int>(number));
5359 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005360 return Heap::NumberFromDouble(DoubleToInteger(number));
5361}
5362
5363
lrn@chromium.org303ada72010-10-27 09:33:13 +00005364static MaybeObject* Runtime_NumberToIntegerMapMinusZero(Arguments args) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005365 NoHandleAllocation ha;
5366 ASSERT(args.length() == 1);
5367
5368 CONVERT_DOUBLE_CHECKED(number, args[0]);
5369
5370 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5371 if (number > 0 && number <= Smi::kMaxValue) {
5372 return Smi::FromInt(static_cast<int>(number));
5373 }
5374
5375 double double_value = DoubleToInteger(number);
5376 // Map both -0 and +0 to +0.
5377 if (double_value == 0) double_value = 0;
5378
5379 return Heap::NumberFromDouble(double_value);
5380}
5381
5382
lrn@chromium.org303ada72010-10-27 09:33:13 +00005383static MaybeObject* Runtime_NumberToJSUint32(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005384 NoHandleAllocation ha;
5385 ASSERT(args.length() == 1);
5386
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005387 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005388 return Heap::NumberFromUint32(number);
5389}
5390
5391
lrn@chromium.org303ada72010-10-27 09:33:13 +00005392static MaybeObject* Runtime_NumberToJSInt32(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005393 NoHandleAllocation ha;
5394 ASSERT(args.length() == 1);
5395
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005396 CONVERT_DOUBLE_CHECKED(number, args[0]);
5397
5398 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5399 if (number > 0 && number <= Smi::kMaxValue) {
5400 return Smi::FromInt(static_cast<int>(number));
5401 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005402 return Heap::NumberFromInt32(DoubleToInt32(number));
5403}
5404
5405
ager@chromium.org870a0b62008-11-04 11:43:05 +00005406// Converts a Number to a Smi, if possible. Returns NaN if the number is not
5407// a small integer.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005408static MaybeObject* Runtime_NumberToSmi(Arguments args) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00005409 NoHandleAllocation ha;
5410 ASSERT(args.length() == 1);
5411
5412 Object* obj = args[0];
5413 if (obj->IsSmi()) {
5414 return obj;
5415 }
5416 if (obj->IsHeapNumber()) {
5417 double value = HeapNumber::cast(obj)->value();
5418 int int_value = FastD2I(value);
5419 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
5420 return Smi::FromInt(int_value);
5421 }
5422 }
5423 return Heap::nan_value();
5424}
5425
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005426
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005427static MaybeObject* Runtime_AllocateHeapNumber(Arguments args) {
5428 NoHandleAllocation ha;
5429 ASSERT(args.length() == 0);
5430 return Heap::AllocateHeapNumber(0);
5431}
5432
5433
lrn@chromium.org303ada72010-10-27 09:33:13 +00005434static MaybeObject* Runtime_NumberAdd(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005435 NoHandleAllocation ha;
5436 ASSERT(args.length() == 2);
5437
5438 CONVERT_DOUBLE_CHECKED(x, args[0]);
5439 CONVERT_DOUBLE_CHECKED(y, args[1]);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00005440 return Heap::NumberFromDouble(x + y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005441}
5442
5443
lrn@chromium.org303ada72010-10-27 09:33:13 +00005444static MaybeObject* Runtime_NumberSub(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005445 NoHandleAllocation ha;
5446 ASSERT(args.length() == 2);
5447
5448 CONVERT_DOUBLE_CHECKED(x, args[0]);
5449 CONVERT_DOUBLE_CHECKED(y, args[1]);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00005450 return Heap::NumberFromDouble(x - y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005451}
5452
5453
lrn@chromium.org303ada72010-10-27 09:33:13 +00005454static MaybeObject* Runtime_NumberMul(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005455 NoHandleAllocation ha;
5456 ASSERT(args.length() == 2);
5457
5458 CONVERT_DOUBLE_CHECKED(x, args[0]);
5459 CONVERT_DOUBLE_CHECKED(y, args[1]);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00005460 return Heap::NumberFromDouble(x * y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005461}
5462
5463
lrn@chromium.org303ada72010-10-27 09:33:13 +00005464static MaybeObject* Runtime_NumberUnaryMinus(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005465 NoHandleAllocation ha;
5466 ASSERT(args.length() == 1);
5467
5468 CONVERT_DOUBLE_CHECKED(x, args[0]);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00005469 return Heap::NumberFromDouble(-x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005470}
5471
5472
lrn@chromium.org303ada72010-10-27 09:33:13 +00005473static MaybeObject* Runtime_NumberAlloc(Arguments args) {
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00005474 NoHandleAllocation ha;
5475 ASSERT(args.length() == 0);
5476
5477 return Heap::NumberFromDouble(9876543210.0);
5478}
5479
5480
lrn@chromium.org303ada72010-10-27 09:33:13 +00005481static MaybeObject* Runtime_NumberDiv(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005482 NoHandleAllocation ha;
5483 ASSERT(args.length() == 2);
5484
5485 CONVERT_DOUBLE_CHECKED(x, args[0]);
5486 CONVERT_DOUBLE_CHECKED(y, args[1]);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00005487 return Heap::NumberFromDouble(x / y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005488}
5489
5490
lrn@chromium.org303ada72010-10-27 09:33:13 +00005491static MaybeObject* Runtime_NumberMod(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005492 NoHandleAllocation ha;
5493 ASSERT(args.length() == 2);
5494
5495 CONVERT_DOUBLE_CHECKED(x, args[0]);
5496 CONVERT_DOUBLE_CHECKED(y, args[1]);
5497
ager@chromium.org3811b432009-10-28 14:53:37 +00005498 x = modulo(x, y);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00005499 // NumberFromDouble may return a Smi instead of a Number object
5500 return Heap::NumberFromDouble(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005501}
5502
5503
lrn@chromium.org303ada72010-10-27 09:33:13 +00005504static MaybeObject* Runtime_StringAdd(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005505 NoHandleAllocation ha;
5506 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005507 CONVERT_CHECKED(String, str1, args[0]);
5508 CONVERT_CHECKED(String, str2, args[1]);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00005509 Counters::string_add_runtime.Increment();
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00005510 return Heap::AllocateConsString(str1, str2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005511}
5512
5513
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005514template <typename sinkchar>
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005515static inline void StringBuilderConcatHelper(String* special,
5516 sinkchar* sink,
5517 FixedArray* fixed_array,
5518 int array_length) {
5519 int position = 0;
5520 for (int i = 0; i < array_length; i++) {
5521 Object* element = fixed_array->get(i);
5522 if (element->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005523 // Smi encoding of position and length.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005524 int encoded_slice = Smi::cast(element)->value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005525 int pos;
5526 int len;
5527 if (encoded_slice > 0) {
5528 // Position and length encoded in one smi.
5529 pos = StringBuilderSubstringPosition::decode(encoded_slice);
5530 len = StringBuilderSubstringLength::decode(encoded_slice);
5531 } else {
5532 // Position and length encoded in two smis.
5533 Object* obj = fixed_array->get(++i);
5534 ASSERT(obj->IsSmi());
5535 pos = Smi::cast(obj)->value();
5536 len = -encoded_slice;
5537 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00005538 String::WriteToFlat(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00005539 sink + position,
5540 pos,
5541 pos + len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005542 position += len;
5543 } else {
5544 String* string = String::cast(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005545 int element_length = string->length();
5546 String::WriteToFlat(string, sink + position, 0, element_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005547 position += element_length;
5548 }
5549 }
5550}
5551
5552
lrn@chromium.org303ada72010-10-27 09:33:13 +00005553static MaybeObject* Runtime_StringBuilderConcat(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005554 NoHandleAllocation ha;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005555 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005556 CONVERT_CHECKED(JSArray, array, args[0]);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005557 if (!args[1]->IsSmi()) {
5558 Top::context()->mark_out_of_memory();
5559 return Failure::OutOfMemoryException();
5560 }
5561 int array_length = Smi::cast(args[1])->value();
5562 CONVERT_CHECKED(String, special, args[2]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005563
5564 // This assumption is used by the slice encoding in one or two smis.
5565 ASSERT(Smi::kMaxValue >= String::kMaxLength);
5566
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005567 int special_length = special->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005568 if (!array->HasFastElements()) {
5569 return Top::Throw(Heap::illegal_argument_symbol());
5570 }
5571 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005572 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005573 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005574 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005575
5576 if (array_length == 0) {
5577 return Heap::empty_string();
5578 } else if (array_length == 1) {
5579 Object* first = fixed_array->get(0);
5580 if (first->IsString()) return first;
5581 }
5582
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005583 bool ascii = special->HasOnlyAsciiChars();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005584 int position = 0;
5585 for (int i = 0; i < array_length; i++) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005586 int increment = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005587 Object* elt = fixed_array->get(i);
5588 if (elt->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005589 // Smi encoding of position and length.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005590 int smi_value = Smi::cast(elt)->value();
5591 int pos;
5592 int len;
5593 if (smi_value > 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005594 // Position and length encoded in one smi.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005595 pos = StringBuilderSubstringPosition::decode(smi_value);
5596 len = StringBuilderSubstringLength::decode(smi_value);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005597 } else {
5598 // Position and length encoded in two smis.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005599 len = -smi_value;
5600 // Get the position and check that it is a positive smi.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005601 i++;
5602 if (i >= array_length) {
5603 return Top::Throw(Heap::illegal_argument_symbol());
5604 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005605 Object* next_smi = fixed_array->get(i);
5606 if (!next_smi->IsSmi()) {
5607 return Top::Throw(Heap::illegal_argument_symbol());
5608 }
5609 pos = Smi::cast(next_smi)->value();
5610 if (pos < 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005611 return Top::Throw(Heap::illegal_argument_symbol());
5612 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005613 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005614 ASSERT(pos >= 0);
5615 ASSERT(len >= 0);
5616 if (pos > special_length || len > special_length - pos) {
5617 return Top::Throw(Heap::illegal_argument_symbol());
5618 }
5619 increment = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005620 } else if (elt->IsString()) {
5621 String* element = String::cast(elt);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005622 int element_length = element->length();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005623 increment = element_length;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005624 if (ascii && !element->HasOnlyAsciiChars()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005625 ascii = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005626 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005627 } else {
5628 return Top::Throw(Heap::illegal_argument_symbol());
5629 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005630 if (increment > String::kMaxLength - position) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005631 Top::context()->mark_out_of_memory();
5632 return Failure::OutOfMemoryException();
5633 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005634 position += increment;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005635 }
5636
5637 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005638 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005639
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005640 if (ascii) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005641 { MaybeObject* maybe_object = Heap::AllocateRawAsciiString(length);
5642 if (!maybe_object->ToObject(&object)) return maybe_object;
5643 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005644 SeqAsciiString* answer = SeqAsciiString::cast(object);
5645 StringBuilderConcatHelper(special,
5646 answer->GetChars(),
5647 fixed_array,
5648 array_length);
5649 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005650 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005651 { MaybeObject* maybe_object = Heap::AllocateRawTwoByteString(length);
5652 if (!maybe_object->ToObject(&object)) return maybe_object;
5653 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005654 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
5655 StringBuilderConcatHelper(special,
5656 answer->GetChars(),
5657 fixed_array,
5658 array_length);
5659 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005660 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005661}
5662
5663
lrn@chromium.org303ada72010-10-27 09:33:13 +00005664static MaybeObject* Runtime_NumberOr(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005665 NoHandleAllocation ha;
5666 ASSERT(args.length() == 2);
5667
5668 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5669 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5670 return Heap::NumberFromInt32(x | y);
5671}
5672
5673
lrn@chromium.org303ada72010-10-27 09:33:13 +00005674static MaybeObject* Runtime_NumberAnd(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005675 NoHandleAllocation ha;
5676 ASSERT(args.length() == 2);
5677
5678 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5679 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5680 return Heap::NumberFromInt32(x & y);
5681}
5682
5683
lrn@chromium.org303ada72010-10-27 09:33:13 +00005684static MaybeObject* Runtime_NumberXor(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005685 NoHandleAllocation ha;
5686 ASSERT(args.length() == 2);
5687
5688 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5689 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5690 return Heap::NumberFromInt32(x ^ y);
5691}
5692
5693
lrn@chromium.org303ada72010-10-27 09:33:13 +00005694static MaybeObject* Runtime_NumberNot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005695 NoHandleAllocation ha;
5696 ASSERT(args.length() == 1);
5697
5698 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5699 return Heap::NumberFromInt32(~x);
5700}
5701
5702
lrn@chromium.org303ada72010-10-27 09:33:13 +00005703static MaybeObject* Runtime_NumberShl(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005704 NoHandleAllocation ha;
5705 ASSERT(args.length() == 2);
5706
5707 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5708 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5709 return Heap::NumberFromInt32(x << (y & 0x1f));
5710}
5711
5712
lrn@chromium.org303ada72010-10-27 09:33:13 +00005713static MaybeObject* Runtime_NumberShr(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005714 NoHandleAllocation ha;
5715 ASSERT(args.length() == 2);
5716
5717 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
5718 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5719 return Heap::NumberFromUint32(x >> (y & 0x1f));
5720}
5721
5722
lrn@chromium.org303ada72010-10-27 09:33:13 +00005723static MaybeObject* Runtime_NumberSar(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005724 NoHandleAllocation ha;
5725 ASSERT(args.length() == 2);
5726
5727 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5728 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5729 return Heap::NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
5730}
5731
5732
lrn@chromium.org303ada72010-10-27 09:33:13 +00005733static MaybeObject* Runtime_NumberEquals(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005734 NoHandleAllocation ha;
5735 ASSERT(args.length() == 2);
5736
5737 CONVERT_DOUBLE_CHECKED(x, args[0]);
5738 CONVERT_DOUBLE_CHECKED(y, args[1]);
5739 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
5740 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
5741 if (x == y) return Smi::FromInt(EQUAL);
5742 Object* result;
5743 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
5744 result = Smi::FromInt(EQUAL);
5745 } else {
5746 result = Smi::FromInt(NOT_EQUAL);
5747 }
5748 return result;
5749}
5750
5751
lrn@chromium.org303ada72010-10-27 09:33:13 +00005752static MaybeObject* Runtime_StringEquals(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005753 NoHandleAllocation ha;
5754 ASSERT(args.length() == 2);
5755
5756 CONVERT_CHECKED(String, x, args[0]);
5757 CONVERT_CHECKED(String, y, args[1]);
5758
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005759 bool not_equal = !x->Equals(y);
5760 // This is slightly convoluted because the value that signifies
5761 // equality is 0 and inequality is 1 so we have to negate the result
5762 // from String::Equals.
5763 ASSERT(not_equal == 0 || not_equal == 1);
5764 STATIC_CHECK(EQUAL == 0);
5765 STATIC_CHECK(NOT_EQUAL == 1);
5766 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005767}
5768
5769
lrn@chromium.org303ada72010-10-27 09:33:13 +00005770static MaybeObject* Runtime_NumberCompare(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005771 NoHandleAllocation ha;
5772 ASSERT(args.length() == 3);
5773
5774 CONVERT_DOUBLE_CHECKED(x, args[0]);
5775 CONVERT_DOUBLE_CHECKED(y, args[1]);
5776 if (isnan(x) || isnan(y)) return args[2];
5777 if (x == y) return Smi::FromInt(EQUAL);
5778 if (isless(x, y)) return Smi::FromInt(LESS);
5779 return Smi::FromInt(GREATER);
5780}
5781
5782
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005783// Compare two Smis as if they were converted to strings and then
5784// compared lexicographically.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005785static MaybeObject* Runtime_SmiLexicographicCompare(Arguments args) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005786 NoHandleAllocation ha;
5787 ASSERT(args.length() == 2);
5788
5789 // Arrays for the individual characters of the two Smis. Smis are
5790 // 31 bit integers and 10 decimal digits are therefore enough.
5791 static int x_elms[10];
5792 static int y_elms[10];
5793
5794 // Extract the integer values from the Smis.
5795 CONVERT_CHECKED(Smi, x, args[0]);
5796 CONVERT_CHECKED(Smi, y, args[1]);
5797 int x_value = x->value();
5798 int y_value = y->value();
5799
5800 // If the integers are equal so are the string representations.
5801 if (x_value == y_value) return Smi::FromInt(EQUAL);
5802
5803 // If one of the integers are zero the normal integer order is the
5804 // same as the lexicographic order of the string representations.
5805 if (x_value == 0 || y_value == 0) return Smi::FromInt(x_value - y_value);
5806
ager@chromium.org32912102009-01-16 10:38:43 +00005807 // If only one of the integers is negative the negative number is
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005808 // smallest because the char code of '-' is less than the char code
5809 // of any digit. Otherwise, we make both values positive.
5810 if (x_value < 0 || y_value < 0) {
5811 if (y_value >= 0) return Smi::FromInt(LESS);
5812 if (x_value >= 0) return Smi::FromInt(GREATER);
5813 x_value = -x_value;
5814 y_value = -y_value;
5815 }
5816
5817 // Convert the integers to arrays of their decimal digits.
5818 int x_index = 0;
5819 int y_index = 0;
5820 while (x_value > 0) {
5821 x_elms[x_index++] = x_value % 10;
5822 x_value /= 10;
5823 }
5824 while (y_value > 0) {
5825 y_elms[y_index++] = y_value % 10;
5826 y_value /= 10;
5827 }
5828
5829 // Loop through the arrays of decimal digits finding the first place
5830 // where they differ.
5831 while (--x_index >= 0 && --y_index >= 0) {
5832 int diff = x_elms[x_index] - y_elms[y_index];
5833 if (diff != 0) return Smi::FromInt(diff);
5834 }
5835
5836 // If one array is a suffix of the other array, the longest array is
5837 // the representation of the largest of the Smis in the
5838 // lexicographic ordering.
5839 return Smi::FromInt(x_index - y_index);
5840}
5841
5842
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005843static Object* StringInputBufferCompare(String* x, String* y) {
5844 static StringInputBuffer bufx;
5845 static StringInputBuffer bufy;
5846 bufx.Reset(x);
5847 bufy.Reset(y);
5848 while (bufx.has_more() && bufy.has_more()) {
5849 int d = bufx.GetNext() - bufy.GetNext();
5850 if (d < 0) return Smi::FromInt(LESS);
5851 else if (d > 0) return Smi::FromInt(GREATER);
5852 }
5853
5854 // x is (non-trivial) prefix of y:
5855 if (bufy.has_more()) return Smi::FromInt(LESS);
5856 // y is prefix of x:
5857 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
5858}
5859
5860
5861static Object* FlatStringCompare(String* x, String* y) {
5862 ASSERT(x->IsFlat());
5863 ASSERT(y->IsFlat());
5864 Object* equal_prefix_result = Smi::FromInt(EQUAL);
5865 int prefix_length = x->length();
5866 if (y->length() < prefix_length) {
5867 prefix_length = y->length();
5868 equal_prefix_result = Smi::FromInt(GREATER);
5869 } else if (y->length() > prefix_length) {
5870 equal_prefix_result = Smi::FromInt(LESS);
5871 }
5872 int r;
5873 if (x->IsAsciiRepresentation()) {
5874 Vector<const char> x_chars = x->ToAsciiVector();
5875 if (y->IsAsciiRepresentation()) {
5876 Vector<const char> y_chars = y->ToAsciiVector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005877 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005878 } else {
5879 Vector<const uc16> y_chars = y->ToUC16Vector();
5880 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
5881 }
5882 } else {
5883 Vector<const uc16> x_chars = x->ToUC16Vector();
5884 if (y->IsAsciiRepresentation()) {
5885 Vector<const char> y_chars = y->ToAsciiVector();
5886 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
5887 } else {
5888 Vector<const uc16> y_chars = y->ToUC16Vector();
5889 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
5890 }
5891 }
5892 Object* result;
5893 if (r == 0) {
5894 result = equal_prefix_result;
5895 } else {
5896 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
5897 }
5898 ASSERT(result == StringInputBufferCompare(x, y));
5899 return result;
5900}
5901
5902
lrn@chromium.org303ada72010-10-27 09:33:13 +00005903static MaybeObject* Runtime_StringCompare(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005904 NoHandleAllocation ha;
5905 ASSERT(args.length() == 2);
5906
5907 CONVERT_CHECKED(String, x, args[0]);
5908 CONVERT_CHECKED(String, y, args[1]);
5909
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005910 Counters::string_compare_runtime.Increment();
5911
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005912 // A few fast case tests before we flatten.
5913 if (x == y) return Smi::FromInt(EQUAL);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005914 if (y->length() == 0) {
5915 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005916 return Smi::FromInt(GREATER);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005917 } else if (x->length() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005918 return Smi::FromInt(LESS);
5919 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005920
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005921 int d = x->Get(0) - y->Get(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005922 if (d < 0) return Smi::FromInt(LESS);
5923 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005924
lrn@chromium.org303ada72010-10-27 09:33:13 +00005925 Object* obj;
5926 { MaybeObject* maybe_obj = Heap::PrepareForCompare(x);
5927 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5928 }
5929 { MaybeObject* maybe_obj = Heap::PrepareForCompare(y);
5930 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5931 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005932
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005933 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
5934 : StringInputBufferCompare(x, y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005935}
5936
5937
lrn@chromium.org303ada72010-10-27 09:33:13 +00005938static MaybeObject* Runtime_Math_acos(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005939 NoHandleAllocation ha;
5940 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005941 Counters::math_acos.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005942
5943 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005944 return TranscendentalCache::Get(TranscendentalCache::ACOS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005945}
5946
5947
lrn@chromium.org303ada72010-10-27 09:33:13 +00005948static MaybeObject* Runtime_Math_asin(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005949 NoHandleAllocation ha;
5950 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005951 Counters::math_asin.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005952
5953 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005954 return TranscendentalCache::Get(TranscendentalCache::ASIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005955}
5956
5957
lrn@chromium.org303ada72010-10-27 09:33:13 +00005958static MaybeObject* Runtime_Math_atan(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005959 NoHandleAllocation ha;
5960 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005961 Counters::math_atan.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005962
5963 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005964 return TranscendentalCache::Get(TranscendentalCache::ATAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005965}
5966
5967
lrn@chromium.org303ada72010-10-27 09:33:13 +00005968static MaybeObject* Runtime_Math_atan2(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005969 NoHandleAllocation ha;
5970 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005971 Counters::math_atan2.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005972
5973 CONVERT_DOUBLE_CHECKED(x, args[0]);
5974 CONVERT_DOUBLE_CHECKED(y, args[1]);
5975 double result;
5976 if (isinf(x) && isinf(y)) {
5977 // Make sure that the result in case of two infinite arguments
5978 // is a multiple of Pi / 4. The sign of the result is determined
5979 // by the first argument (x) and the sign of the second argument
5980 // determines the multiplier: one or three.
5981 static double kPiDividedBy4 = 0.78539816339744830962;
5982 int multiplier = (x < 0) ? -1 : 1;
5983 if (y < 0) multiplier *= 3;
5984 result = multiplier * kPiDividedBy4;
5985 } else {
5986 result = atan2(x, y);
5987 }
5988 return Heap::AllocateHeapNumber(result);
5989}
5990
5991
lrn@chromium.org303ada72010-10-27 09:33:13 +00005992static MaybeObject* Runtime_Math_ceil(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005993 NoHandleAllocation ha;
5994 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005995 Counters::math_ceil.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005996
5997 CONVERT_DOUBLE_CHECKED(x, args[0]);
5998 return Heap::NumberFromDouble(ceiling(x));
5999}
6000
6001
lrn@chromium.org303ada72010-10-27 09:33:13 +00006002static MaybeObject* Runtime_Math_cos(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006003 NoHandleAllocation ha;
6004 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006005 Counters::math_cos.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006006
6007 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006008 return TranscendentalCache::Get(TranscendentalCache::COS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006009}
6010
6011
lrn@chromium.org303ada72010-10-27 09:33:13 +00006012static MaybeObject* Runtime_Math_exp(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006013 NoHandleAllocation ha;
6014 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006015 Counters::math_exp.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006016
6017 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006018 return TranscendentalCache::Get(TranscendentalCache::EXP, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006019}
6020
6021
lrn@chromium.org303ada72010-10-27 09:33:13 +00006022static MaybeObject* Runtime_Math_floor(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006023 NoHandleAllocation ha;
6024 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006025 Counters::math_floor.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006026
6027 CONVERT_DOUBLE_CHECKED(x, args[0]);
6028 return Heap::NumberFromDouble(floor(x));
6029}
6030
6031
lrn@chromium.org303ada72010-10-27 09:33:13 +00006032static MaybeObject* Runtime_Math_log(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006033 NoHandleAllocation ha;
6034 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006035 Counters::math_log.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006036
6037 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006038 return TranscendentalCache::Get(TranscendentalCache::LOG, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006039}
6040
6041
lrn@chromium.org303ada72010-10-27 09:33:13 +00006042static MaybeObject* Runtime_Math_pow(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006043 NoHandleAllocation ha;
6044 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006045 Counters::math_pow.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006046
6047 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006048
6049 // If the second argument is a smi, it is much faster to call the
6050 // custom powi() function than the generic pow().
6051 if (args[1]->IsSmi()) {
6052 int y = Smi::cast(args[1])->value();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006053 return Heap::NumberFromDouble(power_double_int(x, y));
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006054 }
6055
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006056 CONVERT_DOUBLE_CHECKED(y, args[1]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006057 return Heap::AllocateHeapNumber(power_double_double(x, y));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006058}
6059
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006060// Fast version of Math.pow if we know that y is not an integer and
6061// y is not -0.5 or 0.5. Used as slowcase from codegen.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006062static MaybeObject* Runtime_Math_pow_cfunction(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006063 NoHandleAllocation ha;
6064 ASSERT(args.length() == 2);
6065 CONVERT_DOUBLE_CHECKED(x, args[0]);
6066 CONVERT_DOUBLE_CHECKED(y, args[1]);
6067 if (y == 0) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006068 return Smi::FromInt(1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006069 } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006070 return Heap::nan_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006071 } else {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006072 return Heap::AllocateHeapNumber(pow(x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006073 }
6074}
6075
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006076
lrn@chromium.org303ada72010-10-27 09:33:13 +00006077static MaybeObject* Runtime_RoundNumber(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006078 NoHandleAllocation ha;
6079 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006080 Counters::math_round.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006081
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006082 if (!args[0]->IsHeapNumber()) {
6083 // Must be smi. Return the argument unchanged for all the other types
6084 // to make fuzz-natives test happy.
6085 return args[0];
6086 }
6087
6088 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
6089
6090 double value = number->value();
6091 int exponent = number->get_exponent();
6092 int sign = number->get_sign();
6093
6094 // We compare with kSmiValueSize - 3 because (2^30 - 0.1) has exponent 29 and
6095 // should be rounded to 2^30, which is not smi.
6096 if (!sign && exponent <= kSmiValueSize - 3) {
6097 return Smi::FromInt(static_cast<int>(value + 0.5));
6098 }
6099
6100 // If the magnitude is big enough, there's no place for fraction part. If we
6101 // try to add 0.5 to this number, 1.0 will be added instead.
6102 if (exponent >= 52) {
6103 return number;
6104 }
6105
6106 if (sign && value >= -0.5) return Heap::minus_zero_value();
6107
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006108 // Do not call NumberFromDouble() to avoid extra checks.
6109 return Heap::AllocateHeapNumber(floor(value + 0.5));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006110}
6111
6112
lrn@chromium.org303ada72010-10-27 09:33:13 +00006113static MaybeObject* Runtime_Math_sin(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006114 NoHandleAllocation ha;
6115 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006116 Counters::math_sin.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006117
6118 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006119 return TranscendentalCache::Get(TranscendentalCache::SIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006120}
6121
6122
lrn@chromium.org303ada72010-10-27 09:33:13 +00006123static MaybeObject* Runtime_Math_sqrt(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006124 NoHandleAllocation ha;
6125 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006126 Counters::math_sqrt.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006127
6128 CONVERT_DOUBLE_CHECKED(x, args[0]);
6129 return Heap::AllocateHeapNumber(sqrt(x));
6130}
6131
6132
lrn@chromium.org303ada72010-10-27 09:33:13 +00006133static MaybeObject* Runtime_Math_tan(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006134 NoHandleAllocation ha;
6135 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006136 Counters::math_tan.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006137
6138 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006139 return TranscendentalCache::Get(TranscendentalCache::TAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006140}
6141
6142
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006143static int MakeDay(int year, int month, int day) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006144 static const int day_from_month[] = {0, 31, 59, 90, 120, 151,
6145 181, 212, 243, 273, 304, 334};
6146 static const int day_from_month_leap[] = {0, 31, 60, 91, 121, 152,
6147 182, 213, 244, 274, 305, 335};
6148
6149 year += month / 12;
6150 month %= 12;
6151 if (month < 0) {
6152 year--;
6153 month += 12;
6154 }
6155
6156 ASSERT(month >= 0);
6157 ASSERT(month < 12);
6158
6159 // year_delta is an arbitrary number such that:
6160 // a) year_delta = -1 (mod 400)
6161 // b) year + year_delta > 0 for years in the range defined by
6162 // ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of
6163 // Jan 1 1970. This is required so that we don't run into integer
6164 // division of negative numbers.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006165 // c) there shouldn't be an overflow for 32-bit integers in the following
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006166 // operations.
6167 static const int year_delta = 399999;
6168 static const int base_day = 365 * (1970 + year_delta) +
6169 (1970 + year_delta) / 4 -
6170 (1970 + year_delta) / 100 +
6171 (1970 + year_delta) / 400;
6172
6173 int year1 = year + year_delta;
6174 int day_from_year = 365 * year1 +
6175 year1 / 4 -
6176 year1 / 100 +
6177 year1 / 400 -
6178 base_day;
6179
6180 if (year % 4 || (year % 100 == 0 && year % 400 != 0)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006181 return day_from_year + day_from_month[month] + day - 1;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006182 }
6183
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006184 return day_from_year + day_from_month_leap[month] + day - 1;
6185}
6186
6187
lrn@chromium.org303ada72010-10-27 09:33:13 +00006188static MaybeObject* Runtime_DateMakeDay(Arguments args) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006189 NoHandleAllocation ha;
6190 ASSERT(args.length() == 3);
6191
6192 CONVERT_SMI_CHECKED(year, args[0]);
6193 CONVERT_SMI_CHECKED(month, args[1]);
6194 CONVERT_SMI_CHECKED(date, args[2]);
6195
6196 return Smi::FromInt(MakeDay(year, month, date));
6197}
6198
6199
6200static const int kDays4Years[] = {0, 365, 2 * 365, 3 * 365 + 1};
6201static const int kDaysIn4Years = 4 * 365 + 1;
6202static const int kDaysIn100Years = 25 * kDaysIn4Years - 1;
6203static const int kDaysIn400Years = 4 * kDaysIn100Years + 1;
6204static const int kDays1970to2000 = 30 * 365 + 7;
6205static const int kDaysOffset = 1000 * kDaysIn400Years + 5 * kDaysIn400Years -
6206 kDays1970to2000;
6207static const int kYearsOffset = 400000;
6208
6209static const char kDayInYear[] = {
6210 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6211 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6212 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6213 22, 23, 24, 25, 26, 27, 28,
6214 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6215 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6216 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6217 22, 23, 24, 25, 26, 27, 28, 29, 30,
6218 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6219 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6220 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6221 22, 23, 24, 25, 26, 27, 28, 29, 30,
6222 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6223 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6224 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6225 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6226 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6227 22, 23, 24, 25, 26, 27, 28, 29, 30,
6228 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6229 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6230 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6231 22, 23, 24, 25, 26, 27, 28, 29, 30,
6232 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6233 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6234
6235 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6236 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6237 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6238 22, 23, 24, 25, 26, 27, 28,
6239 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6240 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6241 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6242 22, 23, 24, 25, 26, 27, 28, 29, 30,
6243 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6244 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6245 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6246 22, 23, 24, 25, 26, 27, 28, 29, 30,
6247 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6248 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6249 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6250 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6251 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6252 22, 23, 24, 25, 26, 27, 28, 29, 30,
6253 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6254 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6255 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6256 22, 23, 24, 25, 26, 27, 28, 29, 30,
6257 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6258 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6259
6260 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6261 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6262 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6263 22, 23, 24, 25, 26, 27, 28, 29,
6264 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6265 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6266 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6267 22, 23, 24, 25, 26, 27, 28, 29, 30,
6268 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6269 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6270 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6271 22, 23, 24, 25, 26, 27, 28, 29, 30,
6272 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6273 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6274 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6275 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6276 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6277 22, 23, 24, 25, 26, 27, 28, 29, 30,
6278 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6279 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6280 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6281 22, 23, 24, 25, 26, 27, 28, 29, 30,
6282 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6283 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6284
6285 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6286 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6287 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6288 22, 23, 24, 25, 26, 27, 28,
6289 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6290 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6291 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6292 22, 23, 24, 25, 26, 27, 28, 29, 30,
6293 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6294 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6295 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6296 22, 23, 24, 25, 26, 27, 28, 29, 30,
6297 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6298 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6299 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6300 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6301 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6302 22, 23, 24, 25, 26, 27, 28, 29, 30,
6303 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6304 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6305 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6306 22, 23, 24, 25, 26, 27, 28, 29, 30,
6307 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6308 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
6309
6310static const char kMonthInYear[] = {
6311 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6312 0, 0, 0, 0, 0, 0,
6313 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
6314 1, 1, 1,
6315 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
6316 2, 2, 2, 2, 2, 2,
6317 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
6318 3, 3, 3, 3, 3,
6319 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
6320 4, 4, 4, 4, 4, 4,
6321 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
6322 5, 5, 5, 5, 5,
6323 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6324 6, 6, 6, 6, 6, 6,
6325 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
6326 7, 7, 7, 7, 7, 7,
6327 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
6328 8, 8, 8, 8, 8,
6329 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
6330 9, 9, 9, 9, 9, 9,
6331 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6332 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6333 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6334 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6335
6336 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6337 0, 0, 0, 0, 0, 0,
6338 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
6339 1, 1, 1,
6340 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
6341 2, 2, 2, 2, 2, 2,
6342 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
6343 3, 3, 3, 3, 3,
6344 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
6345 4, 4, 4, 4, 4, 4,
6346 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
6347 5, 5, 5, 5, 5,
6348 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6349 6, 6, 6, 6, 6, 6,
6350 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
6351 7, 7, 7, 7, 7, 7,
6352 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
6353 8, 8, 8, 8, 8,
6354 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
6355 9, 9, 9, 9, 9, 9,
6356 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6357 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6358 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6359 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6360
6361 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6362 0, 0, 0, 0, 0, 0,
6363 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
6364 1, 1, 1, 1,
6365 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
6366 2, 2, 2, 2, 2, 2,
6367 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
6368 3, 3, 3, 3, 3,
6369 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
6370 4, 4, 4, 4, 4, 4,
6371 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
6372 5, 5, 5, 5, 5,
6373 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6374 6, 6, 6, 6, 6, 6,
6375 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
6376 7, 7, 7, 7, 7, 7,
6377 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
6378 8, 8, 8, 8, 8,
6379 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
6380 9, 9, 9, 9, 9, 9,
6381 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6382 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6383 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6384 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6385
6386 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6387 0, 0, 0, 0, 0, 0,
6388 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
6389 1, 1, 1,
6390 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
6391 2, 2, 2, 2, 2, 2,
6392 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
6393 3, 3, 3, 3, 3,
6394 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
6395 4, 4, 4, 4, 4, 4,
6396 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
6397 5, 5, 5, 5, 5,
6398 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6399 6, 6, 6, 6, 6, 6,
6400 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
6401 7, 7, 7, 7, 7, 7,
6402 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
6403 8, 8, 8, 8, 8,
6404 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
6405 9, 9, 9, 9, 9, 9,
6406 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6407 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6408 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6409 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11};
6410
6411
6412// This function works for dates from 1970 to 2099.
6413static inline void DateYMDFromTimeAfter1970(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006414 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006415#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00006416 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006417#endif
6418
6419 year = 1970 + (4 * date + 2) / kDaysIn4Years;
6420 date %= kDaysIn4Years;
6421
6422 month = kMonthInYear[date];
6423 day = kDayInYear[date];
6424
6425 ASSERT(MakeDay(year, month, day) == save_date);
6426}
6427
6428
6429static inline void DateYMDFromTimeSlow(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006430 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006431#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00006432 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006433#endif
6434
6435 date += kDaysOffset;
6436 year = 400 * (date / kDaysIn400Years) - kYearsOffset;
6437 date %= kDaysIn400Years;
6438
6439 ASSERT(MakeDay(year, 0, 1) + date == save_date);
6440
6441 date--;
6442 int yd1 = date / kDaysIn100Years;
6443 date %= kDaysIn100Years;
6444 year += 100 * yd1;
6445
6446 date++;
6447 int yd2 = date / kDaysIn4Years;
6448 date %= kDaysIn4Years;
6449 year += 4 * yd2;
6450
6451 date--;
6452 int yd3 = date / 365;
6453 date %= 365;
6454 year += yd3;
6455
6456 bool is_leap = (!yd1 || yd2) && !yd3;
6457
6458 ASSERT(date >= -1);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006459 ASSERT(is_leap || (date >= 0));
6460 ASSERT((date < 365) || (is_leap && (date < 366)));
6461 ASSERT(is_leap == ((year % 4 == 0) && (year % 100 || (year % 400 == 0))));
6462 ASSERT(is_leap || ((MakeDay(year, 0, 1) + date) == save_date));
6463 ASSERT(!is_leap || ((MakeDay(year, 0, 1) + date + 1) == save_date));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006464
6465 if (is_leap) {
6466 day = kDayInYear[2*365 + 1 + date];
6467 month = kMonthInYear[2*365 + 1 + date];
6468 } else {
6469 day = kDayInYear[date];
6470 month = kMonthInYear[date];
6471 }
6472
6473 ASSERT(MakeDay(year, month, day) == save_date);
6474}
6475
6476
6477static inline void DateYMDFromTime(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006478 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006479 if (date >= 0 && date < 32 * kDaysIn4Years) {
6480 DateYMDFromTimeAfter1970(date, year, month, day);
6481 } else {
6482 DateYMDFromTimeSlow(date, year, month, day);
6483 }
6484}
6485
6486
lrn@chromium.org303ada72010-10-27 09:33:13 +00006487static MaybeObject* Runtime_DateYMDFromTime(Arguments args) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006488 NoHandleAllocation ha;
6489 ASSERT(args.length() == 2);
6490
6491 CONVERT_DOUBLE_CHECKED(t, args[0]);
6492 CONVERT_CHECKED(JSArray, res_array, args[1]);
6493
6494 int year, month, day;
6495 DateYMDFromTime(static_cast<int>(floor(t / 86400000)), year, month, day);
6496
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00006497 RUNTIME_ASSERT(res_array->elements()->map() == Heap::fixed_array_map());
6498 FixedArray* elms = FixedArray::cast(res_array->elements());
6499 RUNTIME_ASSERT(elms->length() == 3);
6500
6501 elms->set(0, Smi::FromInt(year));
6502 elms->set(1, Smi::FromInt(month));
6503 elms->set(2, Smi::FromInt(day));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006504
6505 return Heap::undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006506}
6507
6508
lrn@chromium.org303ada72010-10-27 09:33:13 +00006509static MaybeObject* Runtime_NewArgumentsFast(Arguments args) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00006510 NoHandleAllocation ha;
6511 ASSERT(args.length() == 3);
6512
6513 JSFunction* callee = JSFunction::cast(args[0]);
6514 Object** parameters = reinterpret_cast<Object**>(args[1]);
6515 const int length = Smi::cast(args[2])->value();
6516
lrn@chromium.org303ada72010-10-27 09:33:13 +00006517 Object* result;
6518 { MaybeObject* maybe_result = Heap::AllocateArgumentsObject(callee, length);
6519 if (!maybe_result->ToObject(&result)) return maybe_result;
6520 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006521 // Allocate the elements if needed.
6522 if (length > 0) {
6523 // Allocate the fixed array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006524 Object* obj;
6525 { MaybeObject* maybe_obj = Heap::AllocateRawFixedArray(length);
6526 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6527 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006528
6529 AssertNoAllocation no_gc;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006530 FixedArray* array = reinterpret_cast<FixedArray*>(obj);
6531 array->set_map(Heap::fixed_array_map());
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006532 array->set_length(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006533
6534 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006535 for (int i = 0; i < length; i++) {
6536 array->set(i, *--parameters, mode);
6537 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006538 JSObject::cast(result)->set_elements(FixedArray::cast(obj));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00006539 }
6540 return result;
6541}
6542
6543
lrn@chromium.org303ada72010-10-27 09:33:13 +00006544static MaybeObject* Runtime_NewClosure(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006545 HandleScope scope;
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00006546 ASSERT(args.length() == 3);
ager@chromium.org3811b432009-10-28 14:53:37 +00006547 CONVERT_ARG_CHECKED(Context, context, 0);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00006548 CONVERT_ARG_CHECKED(SharedFunctionInfo, shared, 1);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00006549 CONVERT_BOOLEAN_CHECKED(pretenure, args[2]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006550
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00006551 // Allocate global closures in old space and allocate local closures
6552 // in new space. Additionally pretenure closures that are assigned
6553 // directly to properties.
6554 pretenure = pretenure || (context->global_context() == *context);
6555 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006556 Handle<JSFunction> result =
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00006557 Factory::NewFunctionFromSharedFunctionInfo(shared,
6558 context,
6559 pretenure_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006560 return *result;
6561}
6562
lrn@chromium.org303ada72010-10-27 09:33:13 +00006563static MaybeObject* Runtime_NewObjectFromBound(Arguments args) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006564 HandleScope scope;
6565 ASSERT(args.length() == 2);
6566 CONVERT_ARG_CHECKED(JSFunction, function, 0);
6567 CONVERT_ARG_CHECKED(JSArray, params, 1);
6568
whesse@chromium.orge90029b2010-08-02 11:52:17 +00006569 RUNTIME_ASSERT(params->HasFastElements());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006570 FixedArray* fixed = FixedArray::cast(params->elements());
6571
whesse@chromium.orge90029b2010-08-02 11:52:17 +00006572 int fixed_length = Smi::cast(params->length())->value();
6573 SmartPointer<Object**> param_data(NewArray<Object**>(fixed_length));
6574 for (int i = 0; i < fixed_length; i++) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006575 Handle<Object> val = Handle<Object>(fixed->get(i));
6576 param_data[i] = val.location();
6577 }
6578
whesse@chromium.orge90029b2010-08-02 11:52:17 +00006579 bool exception = false;
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006580 Handle<Object> result = Execution::New(
whesse@chromium.orge90029b2010-08-02 11:52:17 +00006581 function, fixed_length, *param_data, &exception);
6582 if (exception) {
6583 return Failure::Exception();
6584 }
6585 ASSERT(!result.is_null());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006586 return *result;
6587}
6588
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006589
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006590static void TrySettingInlineConstructStub(Handle<JSFunction> function) {
ager@chromium.org5c838252010-02-19 08:53:10 +00006591 Handle<Object> prototype = Factory::null_value();
6592 if (function->has_instance_prototype()) {
6593 prototype = Handle<Object>(function->instance_prototype());
6594 }
6595 if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006596 ConstructStubCompiler compiler;
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006597 MaybeObject* code = compiler.CompileConstructStub(*function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006598 if (!code->IsFailure()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00006599 function->shared()->set_construct_stub(
6600 Code::cast(code->ToObjectUnchecked()));
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006601 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006602 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006603}
6604
6605
lrn@chromium.org303ada72010-10-27 09:33:13 +00006606static MaybeObject* Runtime_NewObject(Arguments args) {
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006607 HandleScope scope;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006608 ASSERT(args.length() == 1);
6609
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006610 Handle<Object> constructor = args.at<Object>(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006611
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006612 // If the constructor isn't a proper function we throw a type error.
6613 if (!constructor->IsJSFunction()) {
6614 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
6615 Handle<Object> type_error =
6616 Factory::NewTypeError("not_constructor", arguments);
6617 return Top::Throw(*type_error);
6618 }
6619
6620 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006621
6622 // If function should not have prototype, construction is not allowed. In this
6623 // case generated code bailouts here, since function has no initial_map.
6624 if (!function->should_have_prototype()) {
6625 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
6626 Handle<Object> type_error =
6627 Factory::NewTypeError("not_constructor", arguments);
6628 return Top::Throw(*type_error);
6629 }
6630
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006631#ifdef ENABLE_DEBUGGER_SUPPORT
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006632 // Handle stepping into constructors if step into is active.
6633 if (Debug::StepInActive()) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006634 Debug::HandleStepIn(function, Handle<Object>::null(), 0, true);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006635 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006636#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006637
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006638 if (function->has_initial_map()) {
6639 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006640 // The 'Function' function ignores the receiver object when
6641 // called using 'new' and creates a new JSFunction object that
6642 // is returned. The receiver object is only used for error
6643 // reporting if an error occurs when constructing the new
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006644 // JSFunction. Factory::NewJSObject() should not be used to
6645 // allocate JSFunctions since it does not properly initialize
6646 // the shared part of the function. Since the receiver is
6647 // ignored anyway, we use the global object as the receiver
6648 // instead of a new JSFunction object. This way, errors are
6649 // reported the same way whether or not 'Function' is called
6650 // using 'new'.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006651 return Top::context()->global();
6652 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006653 }
6654
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006655 // The function should be compiled for the optimization hints to be
6656 // available. We cannot use EnsureCompiled because that forces a
6657 // compilation through the shared function info which makes it
6658 // impossible for us to optimize.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006659 Handle<SharedFunctionInfo> shared(function->shared());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006660 if (!function->is_compiled()) CompileLazy(function, CLEAR_EXCEPTION);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006661
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006662 if (!function->has_initial_map() &&
6663 shared->IsInobjectSlackTrackingInProgress()) {
6664 // The tracking is already in progress for another function. We can only
6665 // track one initial_map at a time, so we force the completion before the
6666 // function is called as a constructor for the first time.
6667 shared->CompleteInobjectSlackTracking();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006668 }
6669
6670 bool first_allocation = !shared->live_objects_may_exist();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006671 Handle<JSObject> result = Factory::NewJSObject(function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006672 // Delay setting the stub if inobject slack tracking is in progress.
6673 if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) {
6674 TrySettingInlineConstructStub(function);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006675 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006676
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00006677 Counters::constructed_objects.Increment();
6678 Counters::constructed_objects_runtime.Increment();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006679
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006680 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006681}
6682
6683
lrn@chromium.org303ada72010-10-27 09:33:13 +00006684static MaybeObject* Runtime_FinalizeInstanceSize(Arguments args) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006685 HandleScope scope;
6686 ASSERT(args.length() == 1);
6687
6688 CONVERT_ARG_CHECKED(JSFunction, function, 0);
6689 function->shared()->CompleteInobjectSlackTracking();
6690 TrySettingInlineConstructStub(function);
6691
6692 return Heap::undefined_value();
6693}
6694
6695
lrn@chromium.org303ada72010-10-27 09:33:13 +00006696static MaybeObject* Runtime_LazyCompile(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006697 HandleScope scope;
6698 ASSERT(args.length() == 1);
6699
6700 Handle<JSFunction> function = args.at<JSFunction>(0);
6701#ifdef DEBUG
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00006702 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006703 PrintF("[lazy: ");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006704 function->PrintName();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006705 PrintF("]\n");
6706 }
6707#endif
6708
kasperl@chromium.org71affb52009-05-26 05:44:31 +00006709 // Compile the target function. Here we compile using CompileLazyInLoop in
6710 // order to get the optimized version. This helps code like delta-blue
6711 // that calls performance-critical routines through constructors. A
6712 // constructor call doesn't use a CallIC, it uses a LoadIC followed by a
6713 // direct call. Since the in-loop tracking takes place through CallICs
6714 // this means that things called through constructors are never known to
6715 // be in loops. We compile them as if they are in loops here just in case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006716 ASSERT(!function->is_compiled());
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00006717 if (!CompileLazyInLoop(function, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006718 return Failure::Exception();
6719 }
6720
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006721 // All done. Return the compiled code.
6722 ASSERT(function->is_compiled());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006723 return function->code();
6724}
6725
6726
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006727static MaybeObject* Runtime_LazyRecompile(Arguments args) {
6728 HandleScope scope;
6729 ASSERT(args.length() == 1);
6730 Handle<JSFunction> function = args.at<JSFunction>(0);
6731 // If the function is not optimizable or debugger is active continue using the
6732 // code from the full compiler.
6733 if (!function->shared()->code()->optimizable() ||
6734 Debug::has_break_points()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00006735 if (FLAG_trace_opt) {
6736 PrintF("[failed to optimize ");
6737 function->PrintName();
6738 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n",
6739 function->shared()->code()->optimizable() ? "T" : "F",
6740 Debug::has_break_points() ? "T" : "F");
6741 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006742 function->ReplaceCode(function->shared()->code());
6743 return function->code();
6744 }
6745 if (CompileOptimized(function, AstNode::kNoNumber)) {
6746 return function->code();
6747 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00006748 if (FLAG_trace_opt) {
6749 PrintF("[failed to optimize ");
6750 function->PrintName();
6751 PrintF(": optimized compilation failed]\n");
6752 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006753 function->ReplaceCode(function->shared()->code());
6754 return Failure::Exception();
6755}
6756
6757
6758static MaybeObject* Runtime_NotifyDeoptimized(Arguments args) {
6759 HandleScope scope;
6760 ASSERT(args.length() == 1);
6761 RUNTIME_ASSERT(args[0]->IsSmi());
6762 Deoptimizer::BailoutType type =
6763 static_cast<Deoptimizer::BailoutType>(Smi::cast(args[0])->value());
6764 Deoptimizer* deoptimizer = Deoptimizer::Grab();
6765 ASSERT(Heap::IsAllocationAllowed());
6766 int frames = deoptimizer->output_count();
6767
6768 JavaScriptFrameIterator it;
6769 JavaScriptFrame* frame = NULL;
6770 for (int i = 0; i < frames; i++) {
6771 if (i != 0) it.Advance();
6772 frame = it.frame();
6773 deoptimizer->InsertHeapNumberValues(frames - i - 1, frame);
6774 }
6775 delete deoptimizer;
6776
6777 RUNTIME_ASSERT(frame->function()->IsJSFunction());
6778 Handle<JSFunction> function(JSFunction::cast(frame->function()));
6779 Handle<Object> arguments;
6780 for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00006781 if (frame->GetExpression(i) == Heap::arguments_marker()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006782 if (arguments.is_null()) {
6783 // FunctionGetArguments can't throw an exception, so cast away the
6784 // doubt with an assert.
6785 arguments = Handle<Object>(
6786 Accessors::FunctionGetArguments(*function,
6787 NULL)->ToObjectUnchecked());
6788 ASSERT(*arguments != Heap::null_value());
6789 ASSERT(*arguments != Heap::undefined_value());
6790 }
6791 frame->SetExpression(i, *arguments);
6792 }
6793 }
6794
6795 CompilationCache::MarkForLazyOptimizing(function);
6796 if (type == Deoptimizer::EAGER) {
6797 RUNTIME_ASSERT(function->IsOptimized());
6798 } else {
6799 RUNTIME_ASSERT(!function->IsOptimized());
6800 }
6801
6802 // Avoid doing too much work when running with --always-opt and keep
6803 // the optimized code around.
6804 if (FLAG_always_opt || type == Deoptimizer::LAZY) {
6805 return Heap::undefined_value();
6806 }
6807
6808 // Count the number of optimized activations of the function.
6809 int activations = 0;
6810 while (!it.done()) {
6811 JavaScriptFrame* frame = it.frame();
6812 if (frame->is_optimized() && frame->function() == *function) {
6813 activations++;
6814 }
6815 it.Advance();
6816 }
6817
6818 // TODO(kasperl): For now, we cannot support removing the optimized
6819 // code when we have recursive invocations of the same function.
6820 if (activations == 0) {
6821 if (FLAG_trace_deopt) {
6822 PrintF("[removing optimized code for: ");
6823 function->PrintName();
6824 PrintF("]\n");
6825 }
6826 function->ReplaceCode(function->shared()->code());
6827 }
6828 return Heap::undefined_value();
6829}
6830
6831
6832static MaybeObject* Runtime_NotifyOSR(Arguments args) {
6833 Deoptimizer* deoptimizer = Deoptimizer::Grab();
6834 delete deoptimizer;
6835 return Heap::undefined_value();
6836}
6837
6838
6839static MaybeObject* Runtime_DeoptimizeFunction(Arguments args) {
6840 HandleScope scope;
6841 ASSERT(args.length() == 1);
6842 CONVERT_ARG_CHECKED(JSFunction, function, 0);
6843 if (!function->IsOptimized()) return Heap::undefined_value();
6844
6845 Deoptimizer::DeoptimizeFunction(*function);
6846
6847 return Heap::undefined_value();
6848}
6849
6850
6851static MaybeObject* Runtime_CompileForOnStackReplacement(Arguments args) {
6852 HandleScope scope;
6853 ASSERT(args.length() == 1);
6854 CONVERT_ARG_CHECKED(JSFunction, function, 0);
6855
6856 // We're not prepared to handle a function with arguments object.
6857 ASSERT(!function->shared()->scope_info()->HasArgumentsShadow());
6858
6859 // We have hit a back edge in an unoptimized frame for a function that was
6860 // selected for on-stack replacement. Find the unoptimized code object.
6861 Handle<Code> unoptimized(function->shared()->code());
6862 // Keep track of whether we've succeeded in optimizing.
6863 bool succeeded = unoptimized->optimizable();
6864 if (succeeded) {
6865 // If we are trying to do OSR when there are already optimized
6866 // activations of the function, it means (a) the function is directly or
6867 // indirectly recursive and (b) an optimized invocation has been
6868 // deoptimized so that we are currently in an unoptimized activation.
6869 // Check for optimized activations of this function.
6870 JavaScriptFrameIterator it;
6871 while (succeeded && !it.done()) {
6872 JavaScriptFrame* frame = it.frame();
6873 succeeded = !frame->is_optimized() || frame->function() != *function;
6874 it.Advance();
6875 }
6876 }
6877
6878 int ast_id = AstNode::kNoNumber;
6879 if (succeeded) {
6880 // The top JS function is this one, the PC is somewhere in the
6881 // unoptimized code.
6882 JavaScriptFrameIterator it;
6883 JavaScriptFrame* frame = it.frame();
6884 ASSERT(frame->function() == *function);
6885 ASSERT(frame->code() == *unoptimized);
6886 ASSERT(unoptimized->contains(frame->pc()));
6887
6888 // Use linear search of the unoptimized code's stack check table to find
6889 // the AST id matching the PC.
6890 Address start = unoptimized->instruction_start();
6891 unsigned target_pc_offset = static_cast<unsigned>(frame->pc() - start);
6892 Address table_cursor = start + unoptimized->stack_check_table_start();
6893 uint32_t table_length = Memory::uint32_at(table_cursor);
6894 table_cursor += kIntSize;
6895 for (unsigned i = 0; i < table_length; ++i) {
6896 // Table entries are (AST id, pc offset) pairs.
6897 uint32_t pc_offset = Memory::uint32_at(table_cursor + kIntSize);
6898 if (pc_offset == target_pc_offset) {
6899 ast_id = static_cast<int>(Memory::uint32_at(table_cursor));
6900 break;
6901 }
6902 table_cursor += 2 * kIntSize;
6903 }
6904 ASSERT(ast_id != AstNode::kNoNumber);
6905 if (FLAG_trace_osr) {
6906 PrintF("[replacing on-stack at AST id %d in ", ast_id);
6907 function->PrintName();
6908 PrintF("]\n");
6909 }
6910
6911 // Try to compile the optimized code. A true return value from
6912 // CompileOptimized means that compilation succeeded, not necessarily
6913 // that optimization succeeded.
6914 if (CompileOptimized(function, ast_id) && function->IsOptimized()) {
6915 DeoptimizationInputData* data = DeoptimizationInputData::cast(
6916 function->code()->deoptimization_data());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006917 if (data->OsrPcOffset()->value() >= 0) {
6918 if (FLAG_trace_osr) {
6919 PrintF("[on-stack replacement offset %d in optimized code]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006920 data->OsrPcOffset()->value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006921 }
6922 ASSERT(data->OsrAstId()->value() == ast_id);
6923 } else {
6924 // We may never generate the desired OSR entry if we emit an
6925 // early deoptimize.
6926 succeeded = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006927 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006928 } else {
6929 succeeded = false;
6930 }
6931 }
6932
6933 // Revert to the original stack checks in the original unoptimized code.
6934 if (FLAG_trace_osr) {
6935 PrintF("[restoring original stack checks in ");
6936 function->PrintName();
6937 PrintF("]\n");
6938 }
6939 StackCheckStub check_stub;
6940 Handle<Code> check_code = check_stub.GetCode();
6941 Handle<Code> replacement_code(
6942 Builtins::builtin(Builtins::OnStackReplacement));
ager@chromium.org0ee099b2011-01-25 14:06:47 +00006943 Deoptimizer::RevertStackCheckCode(*unoptimized,
6944 *check_code,
6945 *replacement_code);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006946
6947 // Allow OSR only at nesting level zero again.
6948 unoptimized->set_allow_osr_at_loop_nesting_level(0);
6949
6950 // If the optimization attempt succeeded, return the AST id tagged as a
6951 // smi. This tells the builtin that we need to translate the unoptimized
6952 // frame to an optimized one.
6953 if (succeeded) {
6954 ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
6955 return Smi::FromInt(ast_id);
6956 } else {
6957 return Smi::FromInt(-1);
6958 }
6959}
6960
6961
lrn@chromium.org303ada72010-10-27 09:33:13 +00006962static MaybeObject* Runtime_GetFunctionDelegate(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006963 HandleScope scope;
6964 ASSERT(args.length() == 1);
6965 RUNTIME_ASSERT(!args[0]->IsJSFunction());
6966 return *Execution::GetFunctionDelegate(args.at<Object>(0));
6967}
6968
6969
lrn@chromium.org303ada72010-10-27 09:33:13 +00006970static MaybeObject* Runtime_GetConstructorDelegate(Arguments args) {
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00006971 HandleScope scope;
6972 ASSERT(args.length() == 1);
6973 RUNTIME_ASSERT(!args[0]->IsJSFunction());
6974 return *Execution::GetConstructorDelegate(args.at<Object>(0));
6975}
6976
6977
lrn@chromium.org303ada72010-10-27 09:33:13 +00006978static MaybeObject* Runtime_NewContext(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006979 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00006980 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006981
kasper.lund7276f142008-07-30 08:49:36 +00006982 CONVERT_CHECKED(JSFunction, function, args[0]);
ager@chromium.orgb5737492010-07-15 09:29:43 +00006983 int length = function->shared()->scope_info()->NumberOfContextSlots();
lrn@chromium.org303ada72010-10-27 09:33:13 +00006984 Object* result;
6985 { MaybeObject* maybe_result = Heap::AllocateFunctionContext(length, function);
6986 if (!maybe_result->ToObject(&result)) return maybe_result;
6987 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006988
6989 Top::set_context(Context::cast(result));
6990
kasper.lund7276f142008-07-30 08:49:36 +00006991 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006992}
6993
lrn@chromium.org303ada72010-10-27 09:33:13 +00006994
6995MUST_USE_RESULT static MaybeObject* PushContextHelper(Object* object,
6996 bool is_catch_context) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006997 // Convert the object to a proper JavaScript object.
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00006998 Object* js_object = object;
6999 if (!js_object->IsJSObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007000 MaybeObject* maybe_js_object = js_object->ToObject();
7001 if (!maybe_js_object->ToObject(&js_object)) {
7002 if (!Failure::cast(maybe_js_object)->IsInternalError()) {
7003 return maybe_js_object;
7004 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007005 HandleScope scope;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007006 Handle<Object> handle(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007007 Handle<Object> result =
7008 Factory::NewTypeError("with_expression", HandleVector(&handle, 1));
7009 return Top::Throw(*result);
7010 }
7011 }
7012
lrn@chromium.org303ada72010-10-27 09:33:13 +00007013 Object* result;
7014 { MaybeObject* maybe_result =
7015 Heap::AllocateWithContext(Top::context(),
7016 JSObject::cast(js_object),
7017 is_catch_context);
7018 if (!maybe_result->ToObject(&result)) return maybe_result;
7019 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007020
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007021 Context* context = Context::cast(result);
7022 Top::set_context(context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007023
kasper.lund7276f142008-07-30 08:49:36 +00007024 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007025}
7026
7027
lrn@chromium.org303ada72010-10-27 09:33:13 +00007028static MaybeObject* Runtime_PushContext(Arguments args) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007029 NoHandleAllocation ha;
7030 ASSERT(args.length() == 1);
7031 return PushContextHelper(args[0], false);
7032}
7033
7034
lrn@chromium.org303ada72010-10-27 09:33:13 +00007035static MaybeObject* Runtime_PushCatchContext(Arguments args) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007036 NoHandleAllocation ha;
7037 ASSERT(args.length() == 1);
7038 return PushContextHelper(args[0], true);
7039}
7040
7041
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007042static MaybeObject* Runtime_DeleteContextSlot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007043 HandleScope scope;
7044 ASSERT(args.length() == 2);
7045
7046 CONVERT_ARG_CHECKED(Context, context, 0);
7047 CONVERT_ARG_CHECKED(String, name, 1);
7048
7049 int index;
7050 PropertyAttributes attributes;
7051 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007052 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007053
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007054 // If the slot was not found the result is true.
7055 if (holder.is_null()) {
7056 return Heap::true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007057 }
7058
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007059 // If the slot was found in a context, it should be DONT_DELETE.
7060 if (holder->IsContext()) {
7061 return Heap::false_value();
7062 }
7063
7064 // The slot was found in a JSObject, either a context extension object,
7065 // the global object, or an arguments object. Try to delete it
7066 // (respecting DONT_DELETE). For consistency with V8's usual behavior,
7067 // which allows deleting all parameters in functions that mention
7068 // 'arguments', we do this even for the case of slots found on an
7069 // arguments object. The slot was found on an arguments object if the
7070 // index is non-negative.
7071 Handle<JSObject> object = Handle<JSObject>::cast(holder);
7072 if (index >= 0) {
7073 return object->DeleteElement(index, JSObject::NORMAL_DELETION);
7074 } else {
7075 return object->DeleteProperty(*name, JSObject::NORMAL_DELETION);
7076 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007077}
7078
7079
ager@chromium.orga1645e22009-09-09 19:27:10 +00007080// A mechanism to return a pair of Object pointers in registers (if possible).
7081// How this is achieved is calling convention-dependent.
7082// All currently supported x86 compiles uses calling conventions that are cdecl
7083// variants where a 64-bit value is returned in two 32-bit registers
7084// (edx:eax on ia32, r1:r0 on ARM).
7085// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
7086// In Win64 calling convention, a struct of two pointers is returned in memory,
7087// allocated by the caller, and passed as a pointer in a hidden first parameter.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007088#ifdef V8_HOST_ARCH_64_BIT
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007089struct ObjectPair {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007090 MaybeObject* x;
7091 MaybeObject* y;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007092};
ager@chromium.orga1645e22009-09-09 19:27:10 +00007093
lrn@chromium.org303ada72010-10-27 09:33:13 +00007094static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007095 ObjectPair result = {x, y};
ager@chromium.orga1645e22009-09-09 19:27:10 +00007096 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
7097 // In Win64 they are assigned to a hidden first argument.
7098 return result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007099}
7100#else
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007101typedef uint64_t ObjectPair;
lrn@chromium.org303ada72010-10-27 09:33:13 +00007102static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007103 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007104 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007105}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007106#endif
7107
7108
lrn@chromium.org303ada72010-10-27 09:33:13 +00007109static inline MaybeObject* Unhole(MaybeObject* x,
7110 PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007111 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
7112 USE(attributes);
7113 return x->IsTheHole() ? Heap::undefined_value() : x;
7114}
7115
7116
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007117static JSObject* ComputeReceiverForNonGlobal(JSObject* holder) {
7118 ASSERT(!holder->IsGlobalObject());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007119 Context* top = Top::context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007120 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007121 JSFunction* context_extension_function =
7122 top->global_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007123 // If the holder isn't a context extension object, we just return it
7124 // as the receiver. This allows arguments objects to be used as
7125 // receivers, but only if they are put in the context scope chain
7126 // explicitly via a with-statement.
7127 Object* constructor = holder->map()->constructor();
7128 if (constructor != context_extension_function) return holder;
7129 // Fall back to using the global object as the receiver if the
7130 // property turns out to be a local variable allocated in a context
7131 // extension object - introduced via eval.
7132 return top->global()->global_receiver();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007133}
7134
7135
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007136static ObjectPair LoadContextSlotHelper(Arguments args, bool throw_error) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007137 HandleScope scope;
ager@chromium.orga1645e22009-09-09 19:27:10 +00007138 ASSERT_EQ(2, args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007139
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007140 if (!args[0]->IsContext() || !args[1]->IsString()) {
ager@chromium.org3e875802009-06-29 08:26:34 +00007141 return MakePair(Top::ThrowIllegalOperation(), NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007142 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007143 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007144 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007145
7146 int index;
7147 PropertyAttributes attributes;
7148 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007149 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007150
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007151 // If the index is non-negative, the slot has been found in a local
7152 // variable or a parameter. Read it from the context object or the
7153 // arguments object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007154 if (index >= 0) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007155 // If the "property" we were looking for is a local variable or an
7156 // argument in a context, the receiver is the global object; see
7157 // ECMA-262, 3rd., 10.1.6 and 10.2.3.
7158 JSObject* receiver = Top::context()->global()->global_receiver();
lrn@chromium.org303ada72010-10-27 09:33:13 +00007159 MaybeObject* value = (holder->IsContext())
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007160 ? Context::cast(*holder)->get(index)
7161 : JSObject::cast(*holder)->GetElement(index);
7162 return MakePair(Unhole(value, attributes), receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007163 }
7164
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007165 // If the holder is found, we read the property from it.
7166 if (!holder.is_null() && holder->IsJSObject()) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007167 ASSERT(Handle<JSObject>::cast(holder)->HasProperty(*name));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007168 JSObject* object = JSObject::cast(*holder);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007169 JSObject* receiver;
7170 if (object->IsGlobalObject()) {
7171 receiver = GlobalObject::cast(object)->global_receiver();
7172 } else if (context->is_exception_holder(*holder)) {
7173 receiver = Top::context()->global()->global_receiver();
7174 } else {
7175 receiver = ComputeReceiverForNonGlobal(object);
7176 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007177 // No need to unhole the value here. This is taken care of by the
7178 // GetProperty function.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007179 MaybeObject* value = object->GetProperty(*name);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007180 return MakePair(value, receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007181 }
7182
7183 if (throw_error) {
7184 // The property doesn't exist - throw exception.
7185 Handle<Object> reference_error =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007186 Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007187 return MakePair(Top::Throw(*reference_error), NULL);
7188 } else {
7189 // The property doesn't exist - return undefined
7190 return MakePair(Heap::undefined_value(), Heap::undefined_value());
7191 }
7192}
7193
7194
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007195static ObjectPair Runtime_LoadContextSlot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007196 return LoadContextSlotHelper(args, true);
7197}
7198
7199
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007200static ObjectPair Runtime_LoadContextSlotNoReferenceError(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007201 return LoadContextSlotHelper(args, false);
7202}
7203
7204
lrn@chromium.org303ada72010-10-27 09:33:13 +00007205static MaybeObject* Runtime_StoreContextSlot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007206 HandleScope scope;
7207 ASSERT(args.length() == 3);
7208
7209 Handle<Object> value(args[0]);
7210 CONVERT_ARG_CHECKED(Context, context, 1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007211 CONVERT_ARG_CHECKED(String, name, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007212
7213 int index;
7214 PropertyAttributes attributes;
7215 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007216 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007217
7218 if (index >= 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007219 if (holder->IsContext()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007220 // Ignore if read_only variable.
7221 if ((attributes & READ_ONLY) == 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007222 Handle<Context>::cast(holder)->set(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007223 }
7224 } else {
7225 ASSERT((attributes & READ_ONLY) == 0);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007226 Handle<JSObject>::cast(holder)->SetElement(index, *value)->
7227 ToObjectUnchecked();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007228 }
7229 return *value;
7230 }
7231
7232 // Slow case: The property is not in a FixedArray context.
7233 // It is either in an JSObject extension context or it was not found.
7234 Handle<JSObject> context_ext;
7235
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007236 if (!holder.is_null()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007237 // The property exists in the extension context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007238 context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007239 } else {
7240 // The property was not found. It needs to be stored in the global context.
7241 ASSERT(attributes == ABSENT);
7242 attributes = NONE;
7243 context_ext = Handle<JSObject>(Top::context()->global());
7244 }
7245
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007246 // Set the property, but ignore if read_only variable on the context
7247 // extension object itself.
7248 if ((attributes & READ_ONLY) == 0 ||
7249 (context_ext->GetLocalPropertyAttribute(*name) == ABSENT)) {
whesse@chromium.org023421e2010-12-21 12:19:12 +00007250 Handle<Object> set = SetProperty(context_ext, name, value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007251 if (set.is_null()) {
7252 // Failure::Exception is converted to a null handle in the
7253 // handle-based methods such as SetProperty. We therefore need
7254 // to convert null handles back to exceptions.
7255 ASSERT(Top::has_pending_exception());
7256 return Failure::Exception();
7257 }
7258 }
7259 return *value;
7260}
7261
7262
lrn@chromium.org303ada72010-10-27 09:33:13 +00007263static MaybeObject* Runtime_Throw(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007264 HandleScope scope;
7265 ASSERT(args.length() == 1);
7266
7267 return Top::Throw(args[0]);
7268}
7269
7270
lrn@chromium.org303ada72010-10-27 09:33:13 +00007271static MaybeObject* Runtime_ReThrow(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007272 HandleScope scope;
7273 ASSERT(args.length() == 1);
7274
7275 return Top::ReThrow(args[0]);
7276}
7277
7278
lrn@chromium.org303ada72010-10-27 09:33:13 +00007279static MaybeObject* Runtime_PromoteScheduledException(Arguments args) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007280 ASSERT_EQ(0, args.length());
7281 return Top::PromoteScheduledException();
7282}
7283
7284
lrn@chromium.org303ada72010-10-27 09:33:13 +00007285static MaybeObject* Runtime_ThrowReferenceError(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007286 HandleScope scope;
7287 ASSERT(args.length() == 1);
7288
7289 Handle<Object> name(args[0]);
7290 Handle<Object> reference_error =
7291 Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
7292 return Top::Throw(*reference_error);
7293}
7294
7295
lrn@chromium.org303ada72010-10-27 09:33:13 +00007296static MaybeObject* Runtime_StackOverflow(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007297 NoHandleAllocation na;
7298 return Top::StackOverflow();
7299}
7300
7301
lrn@chromium.org303ada72010-10-27 09:33:13 +00007302static MaybeObject* Runtime_StackGuard(Arguments args) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00007303 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007304
7305 // First check if this is a real stack overflow.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00007306 if (StackGuard::IsStackOverflow()) {
7307 return Runtime_StackOverflow(args);
7308 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007309
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007310 return Execution::HandleStackGuardInterrupt();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007311}
7312
7313
7314// NOTE: These PrintXXX functions are defined for all builds (not just
7315// DEBUG builds) because we may want to be able to trace function
7316// calls in all modes.
7317static void PrintString(String* str) {
7318 // not uncommon to have empty strings
7319 if (str->length() > 0) {
7320 SmartPointer<char> s =
7321 str->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
7322 PrintF("%s", *s);
7323 }
7324}
7325
7326
7327static void PrintObject(Object* obj) {
7328 if (obj->IsSmi()) {
7329 PrintF("%d", Smi::cast(obj)->value());
7330 } else if (obj->IsString() || obj->IsSymbol()) {
7331 PrintString(String::cast(obj));
7332 } else if (obj->IsNumber()) {
7333 PrintF("%g", obj->Number());
7334 } else if (obj->IsFailure()) {
7335 PrintF("<failure>");
7336 } else if (obj->IsUndefined()) {
7337 PrintF("<undefined>");
7338 } else if (obj->IsNull()) {
7339 PrintF("<null>");
7340 } else if (obj->IsTrue()) {
7341 PrintF("<true>");
7342 } else if (obj->IsFalse()) {
7343 PrintF("<false>");
7344 } else {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007345 PrintF("%p", reinterpret_cast<void*>(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007346 }
7347}
7348
7349
7350static int StackSize() {
7351 int n = 0;
7352 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
7353 return n;
7354}
7355
7356
7357static void PrintTransition(Object* result) {
7358 // indentation
7359 { const int nmax = 80;
7360 int n = StackSize();
7361 if (n <= nmax)
7362 PrintF("%4d:%*s", n, n, "");
7363 else
7364 PrintF("%4d:%*s", n, nmax, "...");
7365 }
7366
7367 if (result == NULL) {
7368 // constructor calls
7369 JavaScriptFrameIterator it;
7370 JavaScriptFrame* frame = it.frame();
7371 if (frame->IsConstructor()) PrintF("new ");
7372 // function name
7373 Object* fun = frame->function();
7374 if (fun->IsJSFunction()) {
7375 PrintObject(JSFunction::cast(fun)->shared()->name());
7376 } else {
7377 PrintObject(fun);
7378 }
7379 // function arguments
7380 // (we are intentionally only printing the actually
7381 // supplied parameters, not all parameters required)
7382 PrintF("(this=");
7383 PrintObject(frame->receiver());
7384 const int length = frame->GetProvidedParametersCount();
7385 for (int i = 0; i < length; i++) {
7386 PrintF(", ");
7387 PrintObject(frame->GetParameter(i));
7388 }
7389 PrintF(") {\n");
7390
7391 } else {
7392 // function result
7393 PrintF("} -> ");
7394 PrintObject(result);
7395 PrintF("\n");
7396 }
7397}
7398
7399
lrn@chromium.org303ada72010-10-27 09:33:13 +00007400static MaybeObject* Runtime_TraceEnter(Arguments args) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007401 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007402 NoHandleAllocation ha;
7403 PrintTransition(NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007404 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007405}
7406
7407
lrn@chromium.org303ada72010-10-27 09:33:13 +00007408static MaybeObject* Runtime_TraceExit(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007409 NoHandleAllocation ha;
7410 PrintTransition(args[0]);
7411 return args[0]; // return TOS
7412}
7413
7414
lrn@chromium.org303ada72010-10-27 09:33:13 +00007415static MaybeObject* Runtime_DebugPrint(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007416 NoHandleAllocation ha;
7417 ASSERT(args.length() == 1);
7418
7419#ifdef DEBUG
7420 if (args[0]->IsString()) {
7421 // If we have a string, assume it's a code "marker"
7422 // and print some interesting cpu debugging info.
7423 JavaScriptFrameIterator it;
7424 JavaScriptFrame* frame = it.frame();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00007425 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
7426 frame->fp(), frame->sp(), frame->caller_sp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007427 } else {
7428 PrintF("DebugPrint: ");
7429 }
7430 args[0]->Print();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00007431 if (args[0]->IsHeapObject()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007432 PrintF("\n");
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00007433 HeapObject::cast(args[0])->map()->Print();
7434 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007435#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007436 // ShortPrint is available in release mode. Print is not.
7437 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007438#endif
7439 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00007440 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007441
7442 return args[0]; // return TOS
7443}
7444
7445
lrn@chromium.org303ada72010-10-27 09:33:13 +00007446static MaybeObject* Runtime_DebugTrace(Arguments args) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007447 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007448 NoHandleAllocation ha;
7449 Top::PrintStack();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007450 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007451}
7452
7453
lrn@chromium.org303ada72010-10-27 09:33:13 +00007454static MaybeObject* Runtime_DateCurrentTime(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007455 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00007456 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007457
7458 // According to ECMA-262, section 15.9.1, page 117, the precision of
7459 // the number in a Date object representing a particular instant in
7460 // time is milliseconds. Therefore, we floor the result of getting
7461 // the OS time.
7462 double millis = floor(OS::TimeCurrentMillis());
7463 return Heap::NumberFromDouble(millis);
7464}
7465
7466
lrn@chromium.org303ada72010-10-27 09:33:13 +00007467static MaybeObject* Runtime_DateParseString(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007468 HandleScope scope;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007469 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007470
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007471 CONVERT_ARG_CHECKED(String, str, 0);
7472 FlattenString(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007473
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007474 CONVERT_ARG_CHECKED(JSArray, output, 1);
7475 RUNTIME_ASSERT(output->HasFastElements());
7476
7477 AssertNoAllocation no_allocation;
7478
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007479 FixedArray* output_array = FixedArray::cast(output->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007480 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
7481 bool result;
ager@chromium.org5ec48922009-05-05 07:25:34 +00007482 if (str->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007483 result = DateParser::Parse(str->ToAsciiVector(), output_array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007484 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00007485 ASSERT(str->IsTwoByteRepresentation());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007486 result = DateParser::Parse(str->ToUC16Vector(), output_array);
7487 }
7488
7489 if (result) {
7490 return *output;
7491 } else {
7492 return Heap::null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007493 }
7494}
7495
7496
lrn@chromium.org303ada72010-10-27 09:33:13 +00007497static MaybeObject* Runtime_DateLocalTimezone(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007498 NoHandleAllocation ha;
7499 ASSERT(args.length() == 1);
7500
7501 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00007502 const char* zone = OS::LocalTimezone(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007503 return Heap::AllocateStringFromUtf8(CStrVector(zone));
7504}
7505
7506
lrn@chromium.org303ada72010-10-27 09:33:13 +00007507static MaybeObject* Runtime_DateLocalTimeOffset(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007508 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00007509 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007510
7511 return Heap::NumberFromDouble(OS::LocalTimeOffset());
7512}
7513
7514
lrn@chromium.org303ada72010-10-27 09:33:13 +00007515static MaybeObject* Runtime_DateDaylightSavingsOffset(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007516 NoHandleAllocation ha;
7517 ASSERT(args.length() == 1);
7518
7519 CONVERT_DOUBLE_CHECKED(x, args[0]);
7520 return Heap::NumberFromDouble(OS::DaylightSavingsOffset(x));
7521}
7522
7523
lrn@chromium.org303ada72010-10-27 09:33:13 +00007524static MaybeObject* Runtime_GlobalReceiver(Arguments args) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007525 ASSERT(args.length() == 1);
7526 Object* global = args[0];
7527 if (!global->IsJSGlobalObject()) return Heap::null_value();
7528 return JSGlobalObject::cast(global)->global_receiver();
7529}
7530
7531
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00007532static MaybeObject* Runtime_ParseJson(Arguments args) {
7533 HandleScope scope;
7534 ASSERT_EQ(1, args.length());
7535 CONVERT_ARG_CHECKED(String, source, 0);
7536
7537 Handle<Object> result = JsonParser::Parse(source);
7538 if (result.is_null()) {
7539 // Syntax error or stack overflow in scanner.
7540 ASSERT(Top::has_pending_exception());
7541 return Failure::Exception();
7542 }
7543 return *result;
7544}
7545
7546
lrn@chromium.org303ada72010-10-27 09:33:13 +00007547static MaybeObject* Runtime_CompileString(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007548 HandleScope scope;
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00007549 ASSERT_EQ(1, args.length());
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00007550 CONVERT_ARG_CHECKED(String, source, 0);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007551
ager@chromium.org381abbb2009-02-25 13:23:22 +00007552 // Compile source string in the global context.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007553 Handle<Context> context(Top::context()->global_context());
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007554 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(source,
7555 context,
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00007556 true);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007557 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007558 Handle<JSFunction> fun =
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007559 Factory::NewFunctionFromSharedFunctionInfo(shared, context, NOT_TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007560 return *fun;
7561}
7562
7563
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00007564static ObjectPair CompileGlobalEval(Handle<String> source,
7565 Handle<Object> receiver) {
7566 // Deal with a normal eval call with a string argument. Compile it
7567 // and return the compiled function bound in the local context.
7568 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
7569 source,
7570 Handle<Context>(Top::context()),
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00007571 Top::context()->IsGlobalContext());
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00007572 if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
7573 Handle<JSFunction> compiled = Factory::NewFunctionFromSharedFunctionInfo(
7574 shared,
7575 Handle<Context>(Top::context()),
7576 NOT_TENURED);
7577 return MakePair(*compiled, *receiver);
7578}
7579
7580
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007581static ObjectPair Runtime_ResolvePossiblyDirectEval(Arguments args) {
7582 ASSERT(args.length() == 3);
7583 if (!args[0]->IsJSFunction()) {
7584 return MakePair(Top::ThrowIllegalOperation(), NULL);
7585 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007586
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007587 HandleScope scope;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007588 Handle<JSFunction> callee = args.at<JSFunction>(0);
7589 Handle<Object> receiver; // Will be overwritten.
7590
7591 // Compute the calling context.
7592 Handle<Context> context = Handle<Context>(Top::context());
7593#ifdef DEBUG
7594 // Make sure Top::context() agrees with the old code that traversed
7595 // the stack frames to compute the context.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007596 StackFrameLocator locator;
7597 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007598 ASSERT(Context::cast(frame->context()) == *context);
7599#endif
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007600
7601 // Find where the 'eval' symbol is bound. It is unaliased only if
7602 // it is bound in the global context.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007603 int index = -1;
7604 PropertyAttributes attributes = ABSENT;
7605 while (true) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007606 receiver = context->Lookup(Factory::eval_symbol(), FOLLOW_PROTOTYPE_CHAIN,
7607 &index, &attributes);
iposva@chromium.org245aa852009-02-10 00:49:54 +00007608 // Stop search when eval is found or when the global context is
7609 // reached.
7610 if (attributes != ABSENT || context->IsGlobalContext()) break;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007611 if (context->is_function_context()) {
7612 context = Handle<Context>(Context::cast(context->closure()->context()));
7613 } else {
7614 context = Handle<Context>(context->previous());
7615 }
7616 }
7617
iposva@chromium.org245aa852009-02-10 00:49:54 +00007618 // If eval could not be resolved, it has been deleted and we need to
7619 // throw a reference error.
7620 if (attributes == ABSENT) {
7621 Handle<Object> name = Factory::eval_symbol();
7622 Handle<Object> reference_error =
7623 Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007624 return MakePair(Top::Throw(*reference_error), NULL);
iposva@chromium.org245aa852009-02-10 00:49:54 +00007625 }
7626
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007627 if (!context->IsGlobalContext()) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007628 // 'eval' is not bound in the global context. Just call the function
7629 // with the given arguments. This is not necessarily the global eval.
7630 if (receiver->IsContext()) {
7631 context = Handle<Context>::cast(receiver);
7632 receiver = Handle<Object>(context->get(index));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007633 } else if (receiver->IsJSContextExtensionObject()) {
7634 receiver = Handle<JSObject>(Top::context()->global()->global_receiver());
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007635 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007636 return MakePair(*callee, *receiver);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007637 }
7638
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007639 // 'eval' is bound in the global context, but it may have been overwritten.
7640 // Compare it to the builtin 'GlobalEval' function to make sure.
7641 if (*callee != Top::global_context()->global_eval_fun() ||
7642 !args[1]->IsString()) {
7643 return MakePair(*callee, Top::context()->global()->global_receiver());
7644 }
7645
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00007646 return CompileGlobalEval(args.at<String>(1), args.at<Object>(2));
7647}
7648
7649
7650static ObjectPair Runtime_ResolvePossiblyDirectEvalNoLookup(Arguments args) {
7651 ASSERT(args.length() == 3);
7652 if (!args[0]->IsJSFunction()) {
7653 return MakePair(Top::ThrowIllegalOperation(), NULL);
7654 }
7655
7656 HandleScope scope;
7657 Handle<JSFunction> callee = args.at<JSFunction>(0);
7658
7659 // 'eval' is bound in the global context, but it may have been overwritten.
7660 // Compare it to the builtin 'GlobalEval' function to make sure.
7661 if (*callee != Top::global_context()->global_eval_fun() ||
7662 !args[1]->IsString()) {
7663 return MakePair(*callee, Top::context()->global()->global_receiver());
7664 }
7665
7666 return CompileGlobalEval(args.at<String>(1), args.at<Object>(2));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007667}
7668
7669
lrn@chromium.org303ada72010-10-27 09:33:13 +00007670static MaybeObject* Runtime_SetNewFunctionAttributes(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007671 // This utility adjusts the property attributes for newly created Function
7672 // object ("new Function(...)") by changing the map.
7673 // All it does is changing the prototype property to enumerable
7674 // as specified in ECMA262, 15.3.5.2.
7675 HandleScope scope;
7676 ASSERT(args.length() == 1);
7677 CONVERT_ARG_CHECKED(JSFunction, func, 0);
7678 ASSERT(func->map()->instance_type() ==
7679 Top::function_instance_map()->instance_type());
7680 ASSERT(func->map()->instance_size() ==
7681 Top::function_instance_map()->instance_size());
7682 func->set_map(*Top::function_instance_map());
7683 return *func;
7684}
7685
7686
lrn@chromium.org303ada72010-10-27 09:33:13 +00007687static MaybeObject* Runtime_AllocateInNewSpace(Arguments args) {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00007688 // Allocate a block of memory in NewSpace (filled with a filler).
7689 // Use as fallback for allocation in generated code when NewSpace
7690 // is full.
7691 ASSERT(args.length() == 1);
7692 CONVERT_ARG_CHECKED(Smi, size_smi, 0);
7693 int size = size_smi->value();
7694 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
7695 RUNTIME_ASSERT(size > 0);
7696 static const int kMinFreeNewSpaceAfterGC =
7697 Heap::InitialSemiSpaceSize() * 3/4;
7698 RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007699 Object* allocation;
7700 { MaybeObject* maybe_allocation = Heap::new_space()->AllocateRaw(size);
7701 if (maybe_allocation->ToObject(&allocation)) {
7702 Heap::CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
7703 }
7704 return maybe_allocation;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00007705 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00007706}
7707
7708
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007709// Push an object unto an array of objects if it is not already in the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007710// array. Returns true if the element was pushed on the stack and
7711// false otherwise.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007712static MaybeObject* Runtime_PushIfAbsent(Arguments args) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007713 ASSERT(args.length() == 2);
7714 CONVERT_CHECKED(JSArray, array, args[0]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007715 CONVERT_CHECKED(JSObject, element, args[1]);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007716 RUNTIME_ASSERT(array->HasFastElements());
7717 int length = Smi::cast(array->length())->value();
7718 FixedArray* elements = FixedArray::cast(array->elements());
7719 for (int i = 0; i < length; i++) {
7720 if (elements->get(i) == element) return Heap::false_value();
7721 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00007722 Object* obj;
7723 { MaybeObject* maybe_obj = array->SetFastElement(length, element);
7724 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7725 }
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007726 return Heap::true_value();
7727}
7728
7729
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007730/**
7731 * A simple visitor visits every element of Array's.
7732 * The backend storage can be a fixed array for fast elements case,
7733 * or a dictionary for sparse array. Since Dictionary is a subtype
7734 * of FixedArray, the class can be used by both fast and slow cases.
7735 * The second parameter of the constructor, fast_elements, specifies
7736 * whether the storage is a FixedArray or Dictionary.
7737 *
7738 * An index limit is used to deal with the situation that a result array
7739 * length overflows 32-bit non-negative integer.
7740 */
7741class ArrayConcatVisitor {
7742 public:
7743 ArrayConcatVisitor(Handle<FixedArray> storage,
7744 uint32_t index_limit,
7745 bool fast_elements) :
7746 storage_(storage), index_limit_(index_limit),
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007747 index_offset_(0), fast_elements_(fast_elements) { }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007748
7749 void visit(uint32_t i, Handle<Object> elm) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007750 if (i >= index_limit_ - index_offset_) return;
7751 uint32_t index = index_offset_ + i;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007752
7753 if (fast_elements_) {
7754 ASSERT(index < static_cast<uint32_t>(storage_->length()));
7755 storage_->set(index, *elm);
7756
7757 } else {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00007758 Handle<NumberDictionary> dict = Handle<NumberDictionary>::cast(storage_);
7759 Handle<NumberDictionary> result =
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007760 Factory::DictionaryAtNumberPut(dict, index, elm);
7761 if (!result.is_identical_to(dict))
7762 storage_ = result;
7763 }
7764 }
7765
7766 void increase_index_offset(uint32_t delta) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007767 if (index_limit_ - index_offset_ < delta) {
7768 index_offset_ = index_limit_;
7769 } else {
7770 index_offset_ += delta;
7771 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007772 }
7773
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00007774 Handle<FixedArray> storage() { return storage_; }
7775
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007776 private:
7777 Handle<FixedArray> storage_;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007778 // Limit on the accepted indices. Elements with indices larger than the
7779 // limit are ignored by the visitor.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007780 uint32_t index_limit_;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007781 // Index after last seen index. Always less than or equal to index_limit_.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007782 uint32_t index_offset_;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00007783 const bool fast_elements_;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007784};
7785
7786
ager@chromium.org3811b432009-10-28 14:53:37 +00007787template<class ExternalArrayClass, class ElementType>
7788static uint32_t IterateExternalArrayElements(Handle<JSObject> receiver,
7789 bool elements_are_ints,
7790 bool elements_are_guaranteed_smis,
7791 uint32_t range,
7792 ArrayConcatVisitor* visitor) {
7793 Handle<ExternalArrayClass> array(
7794 ExternalArrayClass::cast(receiver->elements()));
7795 uint32_t len = Min(static_cast<uint32_t>(array->length()), range);
7796
7797 if (visitor != NULL) {
7798 if (elements_are_ints) {
7799 if (elements_are_guaranteed_smis) {
7800 for (uint32_t j = 0; j < len; j++) {
7801 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get(j))));
7802 visitor->visit(j, e);
7803 }
7804 } else {
7805 for (uint32_t j = 0; j < len; j++) {
7806 int64_t val = static_cast<int64_t>(array->get(j));
7807 if (Smi::IsValid(static_cast<intptr_t>(val))) {
7808 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
7809 visitor->visit(j, e);
7810 } else {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007811 Handle<Object> e =
7812 Factory::NewNumber(static_cast<ElementType>(val));
ager@chromium.org3811b432009-10-28 14:53:37 +00007813 visitor->visit(j, e);
7814 }
7815 }
7816 }
7817 } else {
7818 for (uint32_t j = 0; j < len; j++) {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007819 Handle<Object> e = Factory::NewNumber(array->get(j));
ager@chromium.org3811b432009-10-28 14:53:37 +00007820 visitor->visit(j, e);
7821 }
7822 }
7823 }
7824
7825 return len;
7826}
7827
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007828/**
7829 * A helper function that visits elements of a JSObject. Only elements
7830 * whose index between 0 and range (exclusive) are visited.
7831 *
7832 * If the third parameter, visitor, is not NULL, the visitor is called
7833 * with parameters, 'visitor_index_offset + element index' and the element.
7834 *
7835 * It returns the number of visisted elements.
7836 */
7837static uint32_t IterateElements(Handle<JSObject> receiver,
7838 uint32_t range,
7839 ArrayConcatVisitor* visitor) {
7840 uint32_t num_of_elements = 0;
7841
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007842 switch (receiver->GetElementsKind()) {
7843 case JSObject::FAST_ELEMENTS: {
7844 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
7845 uint32_t len = elements->length();
7846 if (range < len) {
7847 len = range;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007848 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007849
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007850 for (uint32_t j = 0; j < len; j++) {
7851 Handle<Object> e(elements->get(j));
7852 if (!e->IsTheHole()) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007853 num_of_elements++;
7854 if (visitor) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007855 visitor->visit(j, e);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007856 }
7857 }
7858 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007859 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007860 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007861 case JSObject::PIXEL_ELEMENTS: {
7862 Handle<PixelArray> pixels(PixelArray::cast(receiver->elements()));
7863 uint32_t len = pixels->length();
7864 if (range < len) {
7865 len = range;
7866 }
7867
7868 for (uint32_t j = 0; j < len; j++) {
7869 num_of_elements++;
7870 if (visitor != NULL) {
7871 Handle<Smi> e(Smi::FromInt(pixels->get(j)));
7872 visitor->visit(j, e);
7873 }
7874 }
7875 break;
7876 }
ager@chromium.org3811b432009-10-28 14:53:37 +00007877 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
7878 num_of_elements =
7879 IterateExternalArrayElements<ExternalByteArray, int8_t>(
7880 receiver, true, true, range, visitor);
7881 break;
7882 }
7883 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
7884 num_of_elements =
7885 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
7886 receiver, true, true, range, visitor);
7887 break;
7888 }
7889 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
7890 num_of_elements =
7891 IterateExternalArrayElements<ExternalShortArray, int16_t>(
7892 receiver, true, true, range, visitor);
7893 break;
7894 }
7895 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
7896 num_of_elements =
7897 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
7898 receiver, true, true, range, visitor);
7899 break;
7900 }
7901 case JSObject::EXTERNAL_INT_ELEMENTS: {
7902 num_of_elements =
7903 IterateExternalArrayElements<ExternalIntArray, int32_t>(
7904 receiver, true, false, range, visitor);
7905 break;
7906 }
7907 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
7908 num_of_elements =
7909 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
7910 receiver, true, false, range, visitor);
7911 break;
7912 }
7913 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
7914 num_of_elements =
7915 IterateExternalArrayElements<ExternalFloatArray, float>(
7916 receiver, false, false, range, visitor);
7917 break;
7918 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007919 case JSObject::DICTIONARY_ELEMENTS: {
7920 Handle<NumberDictionary> dict(receiver->element_dictionary());
7921 uint32_t capacity = dict->Capacity();
7922 for (uint32_t j = 0; j < capacity; j++) {
7923 Handle<Object> k(dict->KeyAt(j));
7924 if (dict->IsKey(*k)) {
7925 ASSERT(k->IsNumber());
7926 uint32_t index = static_cast<uint32_t>(k->Number());
7927 if (index < range) {
7928 num_of_elements++;
7929 if (visitor) {
7930 visitor->visit(index, Handle<Object>(dict->ValueAt(j)));
7931 }
7932 }
7933 }
7934 }
7935 break;
7936 }
7937 default:
7938 UNREACHABLE();
7939 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007940 }
7941
7942 return num_of_elements;
7943}
7944
7945
7946/**
7947 * A helper function that visits elements of an Array object, and elements
7948 * on its prototypes.
7949 *
7950 * Elements on prototypes are visited first, and only elements whose indices
7951 * less than Array length are visited.
7952 *
7953 * If a ArrayConcatVisitor object is given, the visitor is called with
7954 * parameters, element's index + visitor_index_offset and the element.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007955 *
7956 * The returned number of elements is an upper bound on the actual number
7957 * of elements added. If the same element occurs in more than one object
7958 * in the array's prototype chain, it will be counted more than once, but
7959 * will only occur once in the result.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007960 */
7961static uint32_t IterateArrayAndPrototypeElements(Handle<JSArray> array,
7962 ArrayConcatVisitor* visitor) {
7963 uint32_t range = static_cast<uint32_t>(array->length()->Number());
7964 Handle<Object> obj = array;
7965
7966 static const int kEstimatedPrototypes = 3;
7967 List< Handle<JSObject> > objects(kEstimatedPrototypes);
7968
7969 // Visit prototype first. If an element on the prototype is shadowed by
7970 // the inheritor using the same index, the ArrayConcatVisitor visits
7971 // the prototype element before the shadowing element.
7972 // The visitor can simply overwrite the old value by new value using
7973 // the same index. This follows Array::concat semantics.
7974 while (!obj->IsNull()) {
7975 objects.Add(Handle<JSObject>::cast(obj));
7976 obj = Handle<Object>(obj->GetPrototype());
7977 }
7978
7979 uint32_t nof_elements = 0;
7980 for (int i = objects.length() - 1; i >= 0; i--) {
7981 Handle<JSObject> obj = objects[i];
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007982 uint32_t encountered_elements =
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007983 IterateElements(Handle<JSObject>::cast(obj), range, visitor);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007984
7985 if (encountered_elements > JSObject::kMaxElementCount - nof_elements) {
7986 nof_elements = JSObject::kMaxElementCount;
7987 } else {
7988 nof_elements += encountered_elements;
7989 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007990 }
7991
7992 return nof_elements;
7993}
7994
7995
7996/**
7997 * A helper function of Runtime_ArrayConcat.
7998 *
7999 * The first argument is an Array of arrays and objects. It is the
8000 * same as the arguments array of Array::concat JS function.
8001 *
8002 * If an argument is an Array object, the function visits array
8003 * elements. If an argument is not an Array object, the function
8004 * visits the object as if it is an one-element array.
8005 *
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008006 * If the result array index overflows 32-bit unsigned integer, the rounded
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008007 * non-negative number is used as new length. For example, if one
8008 * array length is 2^32 - 1, second array length is 1, the
8009 * concatenated array length is 0.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008010 * TODO(lrn) Change length behavior to ECMAScript 5 specification (length
8011 * is one more than the last array index to get a value assigned).
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008012 */
8013static uint32_t IterateArguments(Handle<JSArray> arguments,
8014 ArrayConcatVisitor* visitor) {
8015 uint32_t visited_elements = 0;
8016 uint32_t num_of_args = static_cast<uint32_t>(arguments->length()->Number());
8017
8018 for (uint32_t i = 0; i < num_of_args; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008019 Object *element;
8020 MaybeObject* maybe_element = arguments->GetElement(i);
8021 // This if() is not expected to fail, but we have the check in the
8022 // interest of hardening the runtime calls.
8023 if (maybe_element->ToObject(&element)) {
8024 Handle<Object> obj(element);
8025 if (obj->IsJSArray()) {
8026 Handle<JSArray> array = Handle<JSArray>::cast(obj);
8027 uint32_t len = static_cast<uint32_t>(array->length()->Number());
8028 uint32_t nof_elements =
8029 IterateArrayAndPrototypeElements(array, visitor);
8030 // Total elements of array and its prototype chain can be more than
8031 // the array length, but ArrayConcat can only concatenate at most
8032 // the array length number of elements. We use the length as an estimate
8033 // for the actual number of elements added.
8034 uint32_t added_elements = (nof_elements > len) ? len : nof_elements;
8035 if (JSArray::kMaxElementCount - visited_elements < added_elements) {
8036 visited_elements = JSArray::kMaxElementCount;
8037 } else {
8038 visited_elements += added_elements;
8039 }
8040 if (visitor) visitor->increase_index_offset(len);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008041 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008042 if (visitor) {
8043 visitor->visit(0, obj);
8044 visitor->increase_index_offset(1);
8045 }
8046 if (visited_elements < JSArray::kMaxElementCount) {
8047 visited_elements++;
8048 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008049 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008050 }
8051 }
8052 return visited_elements;
8053}
8054
8055
8056/**
8057 * Array::concat implementation.
8058 * See ECMAScript 262, 15.4.4.4.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008059 * TODO(lrn): Fix non-compliance for very large concatenations and update to
8060 * following the ECMAScript 5 specification.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008061 */
lrn@chromium.org303ada72010-10-27 09:33:13 +00008062static MaybeObject* Runtime_ArrayConcat(Arguments args) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008063 ASSERT(args.length() == 1);
8064 HandleScope handle_scope;
8065
8066 CONVERT_CHECKED(JSArray, arg_arrays, args[0]);
8067 Handle<JSArray> arguments(arg_arrays);
8068
8069 // Pass 1: estimate the number of elements of the result
8070 // (it could be more than real numbers if prototype has elements).
8071 uint32_t result_length = 0;
8072 uint32_t num_of_args = static_cast<uint32_t>(arguments->length()->Number());
8073
8074 { AssertNoAllocation nogc;
8075 for (uint32_t i = 0; i < num_of_args; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008076 Object* obj;
8077 MaybeObject* maybe_object = arguments->GetElement(i);
8078 // This if() is not expected to fail, but we have the check in the
8079 // interest of hardening the runtime calls.
8080 if (maybe_object->ToObject(&obj)) {
8081 uint32_t length_estimate;
8082 if (obj->IsJSArray()) {
8083 length_estimate =
8084 static_cast<uint32_t>(JSArray::cast(obj)->length()->Number());
8085 } else {
8086 length_estimate = 1;
8087 }
8088 if (JSObject::kMaxElementCount - result_length < length_estimate) {
8089 result_length = JSObject::kMaxElementCount;
8090 break;
8091 }
8092 result_length += length_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008093 }
8094 }
8095 }
8096
8097 // Allocate an empty array, will set length and content later.
8098 Handle<JSArray> result = Factory::NewJSArray(0);
8099
8100 uint32_t estimate_nof_elements = IterateArguments(arguments, NULL);
8101 // If estimated number of elements is more than half of length, a
8102 // fixed array (fast case) is more time and space-efficient than a
8103 // dictionary.
8104 bool fast_case = (estimate_nof_elements * 2) >= result_length;
8105
8106 Handle<FixedArray> storage;
8107 if (fast_case) {
8108 // The backing storage array must have non-existing elements to
8109 // preserve holes across concat operations.
8110 storage = Factory::NewFixedArrayWithHoles(result_length);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008111 Handle<Map> fast_map =
8112 Factory::GetFastElementsMap(Handle<Map>(result->map()));
8113 result->set_map(*fast_map);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008114 } else {
8115 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
8116 uint32_t at_least_space_for = estimate_nof_elements +
8117 (estimate_nof_elements >> 2);
8118 storage = Handle<FixedArray>::cast(
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00008119 Factory::NewNumberDictionary(at_least_space_for));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008120 Handle<Map> slow_map =
8121 Factory::GetSlowElementsMap(Handle<Map>(result->map()));
8122 result->set_map(*slow_map);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008123 }
8124
8125 Handle<Object> len = Factory::NewNumber(static_cast<double>(result_length));
8126
8127 ArrayConcatVisitor visitor(storage, result_length, fast_case);
8128
8129 IterateArguments(arguments, &visitor);
8130
8131 result->set_length(*len);
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00008132 // Please note the storage might have changed in the visitor.
8133 result->set_elements(*visitor.storage());
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008134
8135 return *result;
8136}
8137
8138
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008139// This will not allocate (flatten the string), but it may run
8140// very slowly for very deeply nested ConsStrings. For debugging use only.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008141static MaybeObject* Runtime_GlobalPrint(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008142 NoHandleAllocation ha;
8143 ASSERT(args.length() == 1);
8144
8145 CONVERT_CHECKED(String, string, args[0]);
8146 StringInputBuffer buffer(string);
8147 while (buffer.has_more()) {
8148 uint16_t character = buffer.GetNext();
8149 PrintF("%c", character);
8150 }
8151 return string;
8152}
8153
ager@chromium.org5ec48922009-05-05 07:25:34 +00008154// Moves all own elements of an object, that are below a limit, to positions
8155// starting at zero. All undefined values are placed after non-undefined values,
8156// and are followed by non-existing element. Does not change the length
8157// property.
8158// Returns the number of non-undefined elements collected.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008159static MaybeObject* Runtime_RemoveArrayHoles(Arguments args) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00008160 ASSERT(args.length() == 2);
8161 CONVERT_CHECKED(JSObject, object, args[0]);
8162 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
8163 return object->PrepareElementsForSort(limit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008164}
8165
8166
8167// Move contents of argument 0 (an array) to argument 1 (an array)
lrn@chromium.org303ada72010-10-27 09:33:13 +00008168static MaybeObject* Runtime_MoveArrayContents(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008169 ASSERT(args.length() == 2);
8170 CONVERT_CHECKED(JSArray, from, args[0]);
8171 CONVERT_CHECKED(JSArray, to, args[1]);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00008172 HeapObject* new_elements = from->elements();
lrn@chromium.org303ada72010-10-27 09:33:13 +00008173 MaybeObject* maybe_new_map;
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00008174 if (new_elements->map() == Heap::fixed_array_map() ||
8175 new_elements->map() == Heap::fixed_cow_array_map()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008176 maybe_new_map = to->map()->GetFastElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00008177 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008178 maybe_new_map = to->map()->GetSlowElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00008179 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00008180 Object* new_map;
8181 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00008182 to->set_map(Map::cast(new_map));
8183 to->set_elements(new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008184 to->set_length(from->length());
lrn@chromium.org303ada72010-10-27 09:33:13 +00008185 Object* obj;
8186 { MaybeObject* maybe_obj = from->ResetElements();
8187 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8188 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008189 from->set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008190 return to;
8191}
8192
8193
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008194// How many elements does this object/array have?
lrn@chromium.org303ada72010-10-27 09:33:13 +00008195static MaybeObject* Runtime_EstimateNumberOfElements(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008196 ASSERT(args.length() == 1);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008197 CONVERT_CHECKED(JSObject, object, args[0]);
8198 HeapObject* elements = object->elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008199 if (elements->IsDictionary()) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00008200 return Smi::FromInt(NumberDictionary::cast(elements)->NumberOfElements());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008201 } else if (object->IsJSArray()) {
8202 return JSArray::cast(object)->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008203 } else {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008204 return Smi::FromInt(FixedArray::cast(elements)->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008205 }
8206}
8207
8208
lrn@chromium.org303ada72010-10-27 09:33:13 +00008209static MaybeObject* Runtime_SwapElements(Arguments args) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008210 HandleScope handle_scope;
8211
8212 ASSERT_EQ(3, args.length());
8213
ager@chromium.orgac091b72010-05-05 07:34:42 +00008214 CONVERT_ARG_CHECKED(JSObject, object, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008215 Handle<Object> key1 = args.at<Object>(1);
8216 Handle<Object> key2 = args.at<Object>(2);
8217
8218 uint32_t index1, index2;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008219 if (!key1->ToArrayIndex(&index1)
8220 || !key2->ToArrayIndex(&index2)) {
ager@chromium.orgac091b72010-05-05 07:34:42 +00008221 return Top::ThrowIllegalOperation();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008222 }
8223
ager@chromium.orgac091b72010-05-05 07:34:42 +00008224 Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
8225 Handle<Object> tmp1 = GetElement(jsobject, index1);
8226 Handle<Object> tmp2 = GetElement(jsobject, index2);
8227
8228 SetElement(jsobject, index1, tmp2);
8229 SetElement(jsobject, index2, tmp1);
8230
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008231 return Heap::undefined_value();
8232}
8233
8234
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008235// Returns an array that tells you where in the [0, length) interval an array
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008236// might have elements. Can either return keys (positive integers) or
8237// intervals (pair of a negative integer (-start-1) followed by a
8238// positive (length)) or undefined values.
8239// Intervals can span over some keys that are not in the object.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008240static MaybeObject* Runtime_GetArrayKeys(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008241 ASSERT(args.length() == 2);
8242 HandleScope scope;
ager@chromium.org5ec48922009-05-05 07:25:34 +00008243 CONVERT_ARG_CHECKED(JSObject, array, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008244 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008245 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008246 // Create an array and get all the keys into it, then remove all the
8247 // keys that are not integers in the range 0 to length-1.
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008248 Handle<FixedArray> keys = GetKeysInFixedArrayFor(array, INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008249 int keys_length = keys->length();
8250 for (int i = 0; i < keys_length; i++) {
8251 Object* key = keys->get(i);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008252 uint32_t index = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008253 if (!key->ToArrayIndex(&index) || index >= length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008254 // Zap invalid keys.
8255 keys->set_undefined(i);
8256 }
8257 }
8258 return *Factory::NewJSArrayWithElements(keys);
8259 } else {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008260 ASSERT(array->HasFastElements());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008261 Handle<FixedArray> single_interval = Factory::NewFixedArray(2);
8262 // -1 means start of array.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008263 single_interval->set(0, Smi::FromInt(-1));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008264 uint32_t actual_length =
8265 static_cast<uint32_t>(FixedArray::cast(array->elements())->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +00008266 uint32_t min_length = actual_length < length ? actual_length : length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008267 Handle<Object> length_object =
ager@chromium.org5ec48922009-05-05 07:25:34 +00008268 Factory::NewNumber(static_cast<double>(min_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008269 single_interval->set(1, *length_object);
8270 return *Factory::NewJSArrayWithElements(single_interval);
8271 }
8272}
8273
8274
8275// DefineAccessor takes an optional final argument which is the
8276// property attributes (eg, DONT_ENUM, DONT_DELETE). IMPORTANT: due
8277// to the way accessors are implemented, it is set for both the getter
8278// and setter on the first call to DefineAccessor and ignored on
8279// subsequent calls.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008280static MaybeObject* Runtime_DefineAccessor(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008281 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
8282 // Compute attributes.
8283 PropertyAttributes attributes = NONE;
8284 if (args.length() == 5) {
8285 CONVERT_CHECKED(Smi, attrs, args[4]);
8286 int value = attrs->value();
8287 // Only attribute bits should be set.
8288 ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
8289 attributes = static_cast<PropertyAttributes>(value);
8290 }
8291
8292 CONVERT_CHECKED(JSObject, obj, args[0]);
8293 CONVERT_CHECKED(String, name, args[1]);
8294 CONVERT_CHECKED(Smi, flag, args[2]);
8295 CONVERT_CHECKED(JSFunction, fun, args[3]);
8296 return obj->DefineAccessor(name, flag->value() == 0, fun, attributes);
8297}
8298
8299
lrn@chromium.org303ada72010-10-27 09:33:13 +00008300static MaybeObject* Runtime_LookupAccessor(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008301 ASSERT(args.length() == 3);
8302 CONVERT_CHECKED(JSObject, obj, args[0]);
8303 CONVERT_CHECKED(String, name, args[1]);
8304 CONVERT_CHECKED(Smi, flag, args[2]);
8305 return obj->LookupAccessor(name, flag->value() == 0);
8306}
8307
8308
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008309#ifdef ENABLE_DEBUGGER_SUPPORT
lrn@chromium.org303ada72010-10-27 09:33:13 +00008310static MaybeObject* Runtime_DebugBreak(Arguments args) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008311 ASSERT(args.length() == 0);
8312 return Execution::DebugBreakHelper();
8313}
8314
8315
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008316// Helper functions for wrapping and unwrapping stack frame ids.
8317static Smi* WrapFrameId(StackFrame::Id id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +00008318 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008319 return Smi::FromInt(id >> 2);
8320}
8321
8322
8323static StackFrame::Id UnwrapFrameId(Smi* wrapped) {
8324 return static_cast<StackFrame::Id>(wrapped->value() << 2);
8325}
8326
8327
8328// Adds a JavaScript function as a debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +00008329// args[0]: debug event listener function to set or null or undefined for
8330// clearing the event listener function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008331// args[1]: object supplied during callback
lrn@chromium.org303ada72010-10-27 09:33:13 +00008332static MaybeObject* Runtime_SetDebugEventListener(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008333 ASSERT(args.length() == 2);
iposva@chromium.org245aa852009-02-10 00:49:54 +00008334 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
8335 args[0]->IsUndefined() ||
8336 args[0]->IsNull());
8337 Handle<Object> callback = args.at<Object>(0);
8338 Handle<Object> data = args.at<Object>(1);
8339 Debugger::SetEventListener(callback, data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008340
8341 return Heap::undefined_value();
8342}
8343
8344
lrn@chromium.org303ada72010-10-27 09:33:13 +00008345static MaybeObject* Runtime_Break(Arguments args) {
mads.s.ager31e71382008-08-13 09:32:07 +00008346 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008347 StackGuard::DebugBreak();
8348 return Heap::undefined_value();
8349}
8350
8351
lrn@chromium.org303ada72010-10-27 09:33:13 +00008352static MaybeObject* DebugLookupResultValue(Object* receiver, String* name,
8353 LookupResult* result,
8354 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00008355 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008356 switch (result->type()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008357 case NORMAL:
8358 value = result->holder()->GetNormalizedProperty(result);
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00008359 if (value->IsTheHole()) {
8360 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008361 }
8362 return value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00008363 case FIELD:
8364 value =
8365 JSObject::cast(
8366 result->holder())->FastPropertyAt(result->GetFieldIndex());
8367 if (value->IsTheHole()) {
8368 return Heap::undefined_value();
8369 }
8370 return value;
8371 case CONSTANT_FUNCTION:
8372 return result->GetConstantFunction();
8373 case CALLBACKS: {
8374 Object* structure = result->GetCallbackObject();
kasperl@chromium.org71affb52009-05-26 05:44:31 +00008375 if (structure->IsProxy() || structure->IsAccessorInfo()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008376 MaybeObject* maybe_value = receiver->GetPropertyWithCallback(
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00008377 receiver, structure, name, result->holder());
lrn@chromium.org303ada72010-10-27 09:33:13 +00008378 if (!maybe_value->ToObject(&value)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008379 if (maybe_value->IsRetryAfterGC()) return maybe_value;
lrn@chromium.org303ada72010-10-27 09:33:13 +00008380 ASSERT(maybe_value->IsException());
8381 maybe_value = Top::pending_exception();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00008382 Top::clear_pending_exception();
8383 if (caught_exception != NULL) {
8384 *caught_exception = true;
8385 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00008386 return maybe_value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00008387 }
8388 return value;
8389 } else {
8390 return Heap::undefined_value();
8391 }
8392 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008393 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008394 case MAP_TRANSITION:
8395 case CONSTANT_TRANSITION:
8396 case NULL_DESCRIPTOR:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008397 return Heap::undefined_value();
8398 default:
8399 UNREACHABLE();
8400 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008401 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008402 return Heap::undefined_value();
8403}
8404
8405
ager@chromium.org32912102009-01-16 10:38:43 +00008406// Get debugger related details for an object property.
8407// args[0]: object holding property
8408// args[1]: name of the property
8409//
8410// The array returned contains the following information:
8411// 0: Property value
8412// 1: Property details
8413// 2: Property value is exception
8414// 3: Getter function if defined
8415// 4: Setter function if defined
8416// Items 2-4 are only filled if the property has either a getter or a setter
8417// defined through __defineGetter__ and/or __defineSetter__.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008418static MaybeObject* Runtime_DebugGetPropertyDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008419 HandleScope scope;
8420
8421 ASSERT(args.length() == 2);
8422
8423 CONVERT_ARG_CHECKED(JSObject, obj, 0);
8424 CONVERT_ARG_CHECKED(String, name, 1);
8425
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00008426 // Make sure to set the current context to the context before the debugger was
8427 // entered (if the debugger is entered). The reason for switching context here
8428 // is that for some property lookups (accessors and interceptors) callbacks
8429 // into the embedding application can occour, and the embedding application
8430 // could have the assumption that its own global context is the current
8431 // context and not some internal debugger context.
8432 SaveContext save;
8433 if (Debug::InDebugger()) {
8434 Top::set_context(*Debug::debugger_entry()->GetContext());
8435 }
8436
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008437 // Skip the global proxy as it has no properties and always delegates to the
8438 // real global object.
8439 if (obj->IsJSGlobalProxy()) {
8440 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
8441 }
8442
8443
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008444 // Check if the name is trivially convertible to an index and get the element
8445 // if so.
8446 uint32_t index;
8447 if (name->AsArrayIndex(&index)) {
8448 Handle<FixedArray> details = Factory::NewFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008449 Object* element_or_char;
8450 { MaybeObject* maybe_element_or_char =
8451 Runtime::GetElementOrCharAt(obj, index);
8452 if (!maybe_element_or_char->ToObject(&element_or_char)) {
8453 return maybe_element_or_char;
8454 }
8455 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008456 details->set(0, element_or_char);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008457 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
8458 return *Factory::NewJSArrayWithElements(details);
8459 }
8460
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008461 // Find the number of objects making up this.
8462 int length = LocalPrototypeChainLength(*obj);
8463
8464 // Try local lookup on each of the objects.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008465 Handle<JSObject> jsproto = obj;
8466 for (int i = 0; i < length; i++) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008467 LookupResult result;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008468 jsproto->LocalLookup(*name, &result);
8469 if (result.IsProperty()) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008470 // LookupResult is not GC safe as it holds raw object pointers.
8471 // GC can happen later in this code so put the required fields into
8472 // local variables using handles when required for later use.
8473 PropertyType result_type = result.type();
8474 Handle<Object> result_callback_obj;
8475 if (result_type == CALLBACKS) {
8476 result_callback_obj = Handle<Object>(result.GetCallbackObject());
8477 }
8478 Smi* property_details = result.GetPropertyDetails().AsSmi();
8479 // DebugLookupResultValue can cause GC so details from LookupResult needs
8480 // to be copied to handles before this.
8481 bool caught_exception = false;
lrn@chromium.org303ada72010-10-27 09:33:13 +00008482 Object* raw_value;
8483 { MaybeObject* maybe_raw_value =
8484 DebugLookupResultValue(*obj, *name, &result, &caught_exception);
8485 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
8486 }
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008487 Handle<Object> value(raw_value);
8488
8489 // If the callback object is a fixed array then it contains JavaScript
8490 // getter and/or setter.
8491 bool hasJavaScriptAccessors = result_type == CALLBACKS &&
8492 result_callback_obj->IsFixedArray();
8493 Handle<FixedArray> details =
8494 Factory::NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
8495 details->set(0, *value);
8496 details->set(1, property_details);
8497 if (hasJavaScriptAccessors) {
8498 details->set(2,
8499 caught_exception ? Heap::true_value()
8500 : Heap::false_value());
8501 details->set(3, FixedArray::cast(*result_callback_obj)->get(0));
8502 details->set(4, FixedArray::cast(*result_callback_obj)->get(1));
8503 }
8504
8505 return *Factory::NewJSArrayWithElements(details);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008506 }
8507 if (i < length - 1) {
8508 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
8509 }
8510 }
8511
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008512 return Heap::undefined_value();
8513}
8514
8515
lrn@chromium.org303ada72010-10-27 09:33:13 +00008516static MaybeObject* Runtime_DebugGetProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008517 HandleScope scope;
8518
8519 ASSERT(args.length() == 2);
8520
8521 CONVERT_ARG_CHECKED(JSObject, obj, 0);
8522 CONVERT_ARG_CHECKED(String, name, 1);
8523
8524 LookupResult result;
8525 obj->Lookup(*name, &result);
8526 if (result.IsProperty()) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +00008527 return DebugLookupResultValue(*obj, *name, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008528 }
8529 return Heap::undefined_value();
8530}
8531
8532
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008533// Return the property type calculated from the property details.
8534// args[0]: smi with property details.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008535static MaybeObject* Runtime_DebugPropertyTypeFromDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008536 ASSERT(args.length() == 1);
8537 CONVERT_CHECKED(Smi, details, args[0]);
8538 PropertyType type = PropertyDetails(details).type();
8539 return Smi::FromInt(static_cast<int>(type));
8540}
8541
8542
8543// Return the property attribute calculated from the property details.
8544// args[0]: smi with property details.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008545static MaybeObject* Runtime_DebugPropertyAttributesFromDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008546 ASSERT(args.length() == 1);
8547 CONVERT_CHECKED(Smi, details, args[0]);
8548 PropertyAttributes attributes = PropertyDetails(details).attributes();
8549 return Smi::FromInt(static_cast<int>(attributes));
8550}
8551
8552
8553// Return the property insertion index calculated from the property details.
8554// args[0]: smi with property details.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008555static MaybeObject* Runtime_DebugPropertyIndexFromDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008556 ASSERT(args.length() == 1);
8557 CONVERT_CHECKED(Smi, details, args[0]);
8558 int index = PropertyDetails(details).index();
8559 return Smi::FromInt(index);
8560}
8561
8562
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008563// Return property value from named interceptor.
8564// args[0]: object
8565// args[1]: property name
lrn@chromium.org303ada72010-10-27 09:33:13 +00008566static MaybeObject* Runtime_DebugNamedInterceptorPropertyValue(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008567 HandleScope scope;
8568 ASSERT(args.length() == 2);
8569 CONVERT_ARG_CHECKED(JSObject, obj, 0);
8570 RUNTIME_ASSERT(obj->HasNamedInterceptor());
8571 CONVERT_ARG_CHECKED(String, name, 1);
8572
8573 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008574 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008575}
8576
8577
8578// Return element value from indexed interceptor.
8579// args[0]: object
8580// args[1]: index
lrn@chromium.org303ada72010-10-27 09:33:13 +00008581static MaybeObject* Runtime_DebugIndexedInterceptorElementValue(
8582 Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008583 HandleScope scope;
8584 ASSERT(args.length() == 2);
8585 CONVERT_ARG_CHECKED(JSObject, obj, 0);
8586 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
8587 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
8588
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008589 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008590}
8591
8592
lrn@chromium.org303ada72010-10-27 09:33:13 +00008593static MaybeObject* Runtime_CheckExecutionState(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008594 ASSERT(args.length() >= 1);
8595 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +00008596 // Check that the break id is valid.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00008597 if (Debug::break_id() == 0 || break_id != Debug::break_id()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008598 return Top::Throw(Heap::illegal_execution_state_symbol());
8599 }
8600
8601 return Heap::true_value();
8602}
8603
8604
lrn@chromium.org303ada72010-10-27 09:33:13 +00008605static MaybeObject* Runtime_GetFrameCount(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008606 HandleScope scope;
8607 ASSERT(args.length() == 1);
8608
8609 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008610 Object* result;
8611 { MaybeObject* maybe_result = Runtime_CheckExecutionState(args);
8612 if (!maybe_result->ToObject(&result)) return maybe_result;
8613 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008614
8615 // Count all frames which are relevant to debugging stack trace.
8616 int n = 0;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00008617 StackFrame::Id id = Debug::break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00008618 if (id == StackFrame::NO_ID) {
8619 // If there is no JavaScript stack frame count is 0.
8620 return Smi::FromInt(0);
8621 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008622 for (JavaScriptFrameIterator it(id); !it.done(); it.Advance()) n++;
8623 return Smi::FromInt(n);
8624}
8625
8626
8627static const int kFrameDetailsFrameIdIndex = 0;
8628static const int kFrameDetailsReceiverIndex = 1;
8629static const int kFrameDetailsFunctionIndex = 2;
8630static const int kFrameDetailsArgumentCountIndex = 3;
8631static const int kFrameDetailsLocalCountIndex = 4;
8632static const int kFrameDetailsSourcePositionIndex = 5;
8633static const int kFrameDetailsConstructCallIndex = 6;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008634static const int kFrameDetailsAtReturnIndex = 7;
8635static const int kFrameDetailsDebuggerFrameIndex = 8;
8636static const int kFrameDetailsFirstDynamicIndex = 9;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008637
8638// Return an array with frame details
8639// args[0]: number: break id
8640// args[1]: number: frame index
8641//
8642// The array returned contains the following information:
8643// 0: Frame id
8644// 1: Receiver
8645// 2: Function
8646// 3: Argument count
8647// 4: Local count
8648// 5: Source position
8649// 6: Constructor call
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008650// 7: Is at return
8651// 8: Debugger frame
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008652// Arguments name, value
8653// Locals name, value
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008654// Return value if any
lrn@chromium.org303ada72010-10-27 09:33:13 +00008655static MaybeObject* Runtime_GetFrameDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008656 HandleScope scope;
8657 ASSERT(args.length() == 2);
8658
8659 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008660 Object* check;
8661 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
8662 if (!maybe_check->ToObject(&check)) return maybe_check;
8663 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008664 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
8665
8666 // Find the relevant frame with the requested index.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00008667 StackFrame::Id id = Debug::break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00008668 if (id == StackFrame::NO_ID) {
8669 // If there are no JavaScript stack frames return undefined.
8670 return Heap::undefined_value();
8671 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008672 int count = 0;
8673 JavaScriptFrameIterator it(id);
8674 for (; !it.done(); it.Advance()) {
8675 if (count == index) break;
8676 count++;
8677 }
8678 if (it.done()) return Heap::undefined_value();
8679
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008680 bool is_optimized_frame =
8681 it.frame()->code()->kind() == Code::OPTIMIZED_FUNCTION;
8682
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008683 // Traverse the saved contexts chain to find the active context for the
8684 // selected frame.
8685 SaveContext* save = Top::save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008686 while (save != NULL && !save->below(it.frame())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008687 save = save->prev();
8688 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008689 ASSERT(save != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008690
8691 // Get the frame id.
8692 Handle<Object> frame_id(WrapFrameId(it.frame()->id()));
8693
8694 // Find source position.
kasperl@chromium.org061ef742009-02-27 12:16:20 +00008695 int position = it.frame()->code()->SourcePosition(it.frame()->pc());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008696
8697 // Check for constructor frame.
8698 bool constructor = it.frame()->IsConstructor();
8699
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00008700 // Get scope info and read from it for local variable information.
8701 Handle<JSFunction> function(JSFunction::cast(it.frame()->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +00008702 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00008703 ScopeInfo<> info(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008704
8705 // Get the context.
8706 Handle<Context> context(Context::cast(it.frame()->context()));
8707
8708 // Get the locals names and values into a temporary array.
8709 //
8710 // TODO(1240907): Hide compiler-introduced stack variables
8711 // (e.g. .result)? For users of the debugger, they will probably be
8712 // confusing.
8713 Handle<FixedArray> locals = Factory::NewFixedArray(info.NumberOfLocals() * 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008714
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008715 // Fill in the names of the locals.
8716 for (int i = 0; i < info.NumberOfLocals(); i++) {
8717 locals->set(i * 2, *info.LocalName(i));
8718 }
8719
8720 // Fill in the values of the locals.
8721 for (int i = 0; i < info.NumberOfLocals(); i++) {
8722 if (is_optimized_frame) {
8723 // If we are inspecting an optimized frame use undefined as the
8724 // value for all locals.
8725 //
8726 // TODO(3141533): We should be able to get the correct values
8727 // for locals in optimized frames.
8728 locals->set(i * 2 + 1, Heap::undefined_value());
8729 } else if (i < info.number_of_stack_slots()) {
8730 // Get the value from the stack.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008731 locals->set(i * 2 + 1, it.frame()->GetExpression(i));
8732 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008733 // Traverse the context chain to the function context as all local
8734 // variables stored in the context will be on the function context.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008735 Handle<String> name = info.LocalName(i);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008736 while (!context->is_function_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008737 context = Handle<Context>(context->previous());
8738 }
8739 ASSERT(context->is_function_context());
8740 locals->set(i * 2 + 1,
ager@chromium.orgb5737492010-07-15 09:29:43 +00008741 context->get(scope_info->ContextSlotIndex(*name, NULL)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008742 }
8743 }
8744
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008745 // Check whether this frame is positioned at return. If not top
8746 // frame or if the frame is optimized it cannot be at a return.
8747 bool at_return = false;
8748 if (!is_optimized_frame && index == 0) {
8749 at_return = Debug::IsBreakAtReturn(it.frame());
8750 }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008751
8752 // If positioned just before return find the value to be returned and add it
8753 // to the frame information.
8754 Handle<Object> return_value = Factory::undefined_value();
8755 if (at_return) {
8756 StackFrameIterator it2;
8757 Address internal_frame_sp = NULL;
8758 while (!it2.done()) {
8759 if (it2.frame()->is_internal()) {
8760 internal_frame_sp = it2.frame()->sp();
8761 } else {
8762 if (it2.frame()->is_java_script()) {
8763 if (it2.frame()->id() == it.frame()->id()) {
8764 // The internal frame just before the JavaScript frame contains the
8765 // value to return on top. A debug break at return will create an
8766 // internal frame to store the return value (eax/rax/r0) before
8767 // entering the debug break exit frame.
8768 if (internal_frame_sp != NULL) {
8769 return_value =
8770 Handle<Object>(Memory::Object_at(internal_frame_sp));
8771 break;
8772 }
8773 }
8774 }
8775
8776 // Indicate that the previous frame was not an internal frame.
8777 internal_frame_sp = NULL;
8778 }
8779 it2.Advance();
8780 }
8781 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008782
8783 // Now advance to the arguments adapter frame (if any). It contains all
8784 // the provided parameters whereas the function frame always have the number
8785 // of arguments matching the functions parameters. The rest of the
8786 // information (except for what is collected above) is the same.
8787 it.AdvanceToArgumentsFrame();
8788
8789 // Find the number of arguments to fill. At least fill the number of
8790 // parameters for the function and fill more if more parameters are provided.
8791 int argument_count = info.number_of_parameters();
8792 if (argument_count < it.frame()->GetProvidedParametersCount()) {
8793 argument_count = it.frame()->GetProvidedParametersCount();
8794 }
8795
8796 // Calculate the size of the result.
8797 int details_size = kFrameDetailsFirstDynamicIndex +
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008798 2 * (argument_count + info.NumberOfLocals()) +
8799 (at_return ? 1 : 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008800 Handle<FixedArray> details = Factory::NewFixedArray(details_size);
8801
8802 // Add the frame id.
8803 details->set(kFrameDetailsFrameIdIndex, *frame_id);
8804
8805 // Add the function (same as in function frame).
8806 details->set(kFrameDetailsFunctionIndex, it.frame()->function());
8807
8808 // Add the arguments count.
8809 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
8810
8811 // Add the locals count
8812 details->set(kFrameDetailsLocalCountIndex,
8813 Smi::FromInt(info.NumberOfLocals()));
8814
8815 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +00008816 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008817 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
8818 } else {
8819 details->set(kFrameDetailsSourcePositionIndex, Heap::undefined_value());
8820 }
8821
8822 // Add the constructor information.
8823 details->set(kFrameDetailsConstructCallIndex, Heap::ToBoolean(constructor));
8824
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008825 // Add the at return information.
8826 details->set(kFrameDetailsAtReturnIndex, Heap::ToBoolean(at_return));
8827
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008828 // Add information on whether this frame is invoked in the debugger context.
8829 details->set(kFrameDetailsDebuggerFrameIndex,
8830 Heap::ToBoolean(*save->context() == *Debug::debug_context()));
8831
8832 // Fill the dynamic part.
8833 int details_index = kFrameDetailsFirstDynamicIndex;
8834
8835 // Add arguments name and value.
8836 for (int i = 0; i < argument_count; i++) {
8837 // Name of the argument.
8838 if (i < info.number_of_parameters()) {
8839 details->set(details_index++, *info.parameter_name(i));
8840 } else {
8841 details->set(details_index++, Heap::undefined_value());
8842 }
8843
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008844 // Parameter value. If we are inspecting an optimized frame, use
8845 // undefined as the value.
8846 //
8847 // TODO(3141533): We should be able to get the actual parameter
8848 // value for optimized frames.
8849 if (!is_optimized_frame &&
8850 (i < it.frame()->GetProvidedParametersCount())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008851 details->set(details_index++, it.frame()->GetParameter(i));
8852 } else {
8853 details->set(details_index++, Heap::undefined_value());
8854 }
8855 }
8856
8857 // Add locals name and value from the temporary copy from the function frame.
8858 for (int i = 0; i < info.NumberOfLocals() * 2; i++) {
8859 details->set(details_index++, locals->get(i));
8860 }
8861
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008862 // Add the value being returned.
8863 if (at_return) {
8864 details->set(details_index++, *return_value);
8865 }
8866
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008867 // Add the receiver (same as in function frame).
8868 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
8869 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
8870 Handle<Object> receiver(it.frame()->receiver());
8871 if (!receiver->IsJSObject()) {
8872 // If the receiver is NOT a JSObject we have hit an optimization
8873 // where a value object is not converted into a wrapped JS objects.
8874 // To hide this optimization from the debugger, we wrap the receiver
8875 // by creating correct wrapper object based on the calling frame's
8876 // global context.
8877 it.Advance();
8878 Handle<Context> calling_frames_global_context(
8879 Context::cast(Context::cast(it.frame()->context())->global_context()));
8880 receiver = Factory::ToObject(receiver, calling_frames_global_context);
8881 }
8882 details->set(kFrameDetailsReceiverIndex, *receiver);
8883
8884 ASSERT_EQ(details_size, details_index);
8885 return *Factory::NewJSArrayWithElements(details);
8886}
8887
8888
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008889// Copy all the context locals into an object used to materialize a scope.
ager@chromium.orgb5737492010-07-15 09:29:43 +00008890static void CopyContextLocalsToScopeObject(
8891 Handle<SerializedScopeInfo> serialized_scope_info,
8892 ScopeInfo<>& scope_info,
8893 Handle<Context> context,
8894 Handle<JSObject> scope_object) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008895 // Fill all context locals to the context extension.
8896 for (int i = Context::MIN_CONTEXT_SLOTS;
8897 i < scope_info.number_of_context_slots();
8898 i++) {
ager@chromium.orgb5737492010-07-15 09:29:43 +00008899 int context_index = serialized_scope_info->ContextSlotIndex(
8900 *scope_info.context_slot_name(i), NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008901
8902 // Don't include the arguments shadow (.arguments) context variable.
8903 if (*scope_info.context_slot_name(i) != Heap::arguments_shadow_symbol()) {
8904 SetProperty(scope_object,
8905 scope_info.context_slot_name(i),
8906 Handle<Object>(context->get(context_index)), NONE);
8907 }
8908 }
8909}
8910
8911
8912// Create a plain JSObject which materializes the local scope for the specified
8913// frame.
8914static Handle<JSObject> MaterializeLocalScope(JavaScriptFrame* frame) {
8915 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00008916 Handle<SharedFunctionInfo> shared(function->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +00008917 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
8918 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008919
8920 // Allocate and initialize a JSObject with all the arguments, stack locals
8921 // heap locals and extension properties of the debugged function.
8922 Handle<JSObject> local_scope = Factory::NewJSObject(Top::object_function());
8923
8924 // First fill all parameters.
8925 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
8926 SetProperty(local_scope,
8927 scope_info.parameter_name(i),
8928 Handle<Object>(frame->GetParameter(i)), NONE);
8929 }
8930
8931 // Second fill all stack locals.
8932 for (int i = 0; i < scope_info.number_of_stack_slots(); i++) {
8933 SetProperty(local_scope,
8934 scope_info.stack_slot_name(i),
8935 Handle<Object>(frame->GetExpression(i)), NONE);
8936 }
8937
8938 // Third fill all context locals.
8939 Handle<Context> frame_context(Context::cast(frame->context()));
8940 Handle<Context> function_context(frame_context->fcontext());
ager@chromium.orgb5737492010-07-15 09:29:43 +00008941 CopyContextLocalsToScopeObject(serialized_scope_info, scope_info,
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008942 function_context, local_scope);
8943
8944 // Finally copy any properties from the function context extension. This will
8945 // be variables introduced by eval.
8946 if (function_context->closure() == *function) {
8947 if (function_context->has_extension() &&
8948 !function_context->IsGlobalContext()) {
8949 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008950 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008951 for (int i = 0; i < keys->length(); i++) {
8952 // Names of variables introduced by eval are strings.
8953 ASSERT(keys->get(i)->IsString());
8954 Handle<String> key(String::cast(keys->get(i)));
8955 SetProperty(local_scope, key, GetProperty(ext, key), NONE);
8956 }
8957 }
8958 }
8959 return local_scope;
8960}
8961
8962
8963// Create a plain JSObject which materializes the closure content for the
8964// context.
8965static Handle<JSObject> MaterializeClosure(Handle<Context> context) {
8966 ASSERT(context->is_function_context());
8967
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00008968 Handle<SharedFunctionInfo> shared(context->closure()->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +00008969 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
8970 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008971
8972 // Allocate and initialize a JSObject with all the content of theis function
8973 // closure.
8974 Handle<JSObject> closure_scope = Factory::NewJSObject(Top::object_function());
8975
8976 // Check whether the arguments shadow object exists.
8977 int arguments_shadow_index =
ager@chromium.orgb5737492010-07-15 09:29:43 +00008978 shared->scope_info()->ContextSlotIndex(Heap::arguments_shadow_symbol(),
8979 NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008980 if (arguments_shadow_index >= 0) {
8981 // In this case all the arguments are available in the arguments shadow
8982 // object.
8983 Handle<JSObject> arguments_shadow(
8984 JSObject::cast(context->get(arguments_shadow_index)));
8985 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008986 // We don't expect exception-throwing getters on the arguments shadow.
8987 Object* element = arguments_shadow->GetElement(i)->ToObjectUnchecked();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008988 SetProperty(closure_scope,
8989 scope_info.parameter_name(i),
lrn@chromium.org303ada72010-10-27 09:33:13 +00008990 Handle<Object>(element),
8991 NONE);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008992 }
8993 }
8994
8995 // Fill all context locals to the context extension.
ager@chromium.orgb5737492010-07-15 09:29:43 +00008996 CopyContextLocalsToScopeObject(serialized_scope_info, scope_info,
8997 context, closure_scope);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008998
8999 // Finally copy any properties from the function context extension. This will
9000 // be variables introduced by eval.
9001 if (context->has_extension()) {
9002 Handle<JSObject> ext(JSObject::cast(context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009003 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009004 for (int i = 0; i < keys->length(); i++) {
9005 // Names of variables introduced by eval are strings.
9006 ASSERT(keys->get(i)->IsString());
9007 Handle<String> key(String::cast(keys->get(i)));
9008 SetProperty(closure_scope, key, GetProperty(ext, key), NONE);
9009 }
9010 }
9011
9012 return closure_scope;
9013}
9014
9015
9016// Iterate over the actual scopes visible from a stack frame. All scopes are
9017// backed by an actual context except the local scope, which is inserted
9018// "artifically" in the context chain.
9019class ScopeIterator {
9020 public:
9021 enum ScopeType {
9022 ScopeTypeGlobal = 0,
9023 ScopeTypeLocal,
9024 ScopeTypeWith,
ager@chromium.orga1645e22009-09-09 19:27:10 +00009025 ScopeTypeClosure,
9026 // Every catch block contains an implicit with block (its parameter is
9027 // a JSContextExtensionObject) that extends current scope with a variable
9028 // holding exception object. Such with blocks are treated as scopes of their
9029 // own type.
9030 ScopeTypeCatch
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009031 };
9032
9033 explicit ScopeIterator(JavaScriptFrame* frame)
9034 : frame_(frame),
9035 function_(JSFunction::cast(frame->function())),
9036 context_(Context::cast(frame->context())),
9037 local_done_(false),
9038 at_local_(false) {
9039
9040 // Check whether the first scope is actually a local scope.
9041 if (context_->IsGlobalContext()) {
9042 // If there is a stack slot for .result then this local scope has been
9043 // created for evaluating top level code and it is not a real local scope.
9044 // Checking for the existence of .result seems fragile, but the scope info
9045 // saved with the code object does not otherwise have that information.
ager@chromium.orgb5737492010-07-15 09:29:43 +00009046 int index = function_->shared()->scope_info()->
9047 StackSlotIndex(Heap::result_symbol());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009048 at_local_ = index < 0;
9049 } else if (context_->is_function_context()) {
9050 at_local_ = true;
9051 }
9052 }
9053
9054 // More scopes?
9055 bool Done() { return context_.is_null(); }
9056
9057 // Move to the next scope.
9058 void Next() {
9059 // If at a local scope mark the local scope as passed.
9060 if (at_local_) {
9061 at_local_ = false;
9062 local_done_ = true;
9063
9064 // If the current context is not associated with the local scope the
9065 // current context is the next real scope, so don't move to the next
9066 // context in this case.
9067 if (context_->closure() != *function_) {
9068 return;
9069 }
9070 }
9071
9072 // The global scope is always the last in the chain.
9073 if (context_->IsGlobalContext()) {
9074 context_ = Handle<Context>();
9075 return;
9076 }
9077
9078 // Move to the next context.
9079 if (context_->is_function_context()) {
9080 context_ = Handle<Context>(Context::cast(context_->closure()->context()));
9081 } else {
9082 context_ = Handle<Context>(context_->previous());
9083 }
9084
9085 // If passing the local scope indicate that the current scope is now the
9086 // local scope.
9087 if (!local_done_ &&
9088 (context_->IsGlobalContext() || (context_->is_function_context()))) {
9089 at_local_ = true;
9090 }
9091 }
9092
9093 // Return the type of the current scope.
9094 int Type() {
9095 if (at_local_) {
9096 return ScopeTypeLocal;
9097 }
9098 if (context_->IsGlobalContext()) {
9099 ASSERT(context_->global()->IsGlobalObject());
9100 return ScopeTypeGlobal;
9101 }
9102 if (context_->is_function_context()) {
9103 return ScopeTypeClosure;
9104 }
9105 ASSERT(context_->has_extension());
ager@chromium.orga1645e22009-09-09 19:27:10 +00009106 // Current scope is either an explicit with statement or a with statement
9107 // implicitely generated for a catch block.
9108 // If the extension object here is a JSContextExtensionObject then
9109 // current with statement is one frome a catch block otherwise it's a
9110 // regular with statement.
9111 if (context_->extension()->IsJSContextExtensionObject()) {
9112 return ScopeTypeCatch;
9113 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009114 return ScopeTypeWith;
9115 }
9116
9117 // Return the JavaScript object with the content of the current scope.
9118 Handle<JSObject> ScopeObject() {
9119 switch (Type()) {
9120 case ScopeIterator::ScopeTypeGlobal:
9121 return Handle<JSObject>(CurrentContext()->global());
9122 break;
9123 case ScopeIterator::ScopeTypeLocal:
9124 // Materialize the content of the local scope into a JSObject.
9125 return MaterializeLocalScope(frame_);
9126 break;
9127 case ScopeIterator::ScopeTypeWith:
ager@chromium.orga1645e22009-09-09 19:27:10 +00009128 case ScopeIterator::ScopeTypeCatch:
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009129 // Return the with object.
9130 return Handle<JSObject>(CurrentContext()->extension());
9131 break;
9132 case ScopeIterator::ScopeTypeClosure:
9133 // Materialize the content of the closure scope into a JSObject.
9134 return MaterializeClosure(CurrentContext());
9135 break;
9136 }
9137 UNREACHABLE();
9138 return Handle<JSObject>();
9139 }
9140
9141 // Return the context for this scope. For the local context there might not
9142 // be an actual context.
9143 Handle<Context> CurrentContext() {
9144 if (at_local_ && context_->closure() != *function_) {
9145 return Handle<Context>();
9146 }
9147 return context_;
9148 }
9149
9150#ifdef DEBUG
9151 // Debug print of the content of the current scope.
9152 void DebugPrint() {
9153 switch (Type()) {
9154 case ScopeIterator::ScopeTypeGlobal:
9155 PrintF("Global:\n");
9156 CurrentContext()->Print();
9157 break;
9158
9159 case ScopeIterator::ScopeTypeLocal: {
9160 PrintF("Local:\n");
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009161 ScopeInfo<> scope_info(function_->shared()->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009162 scope_info.Print();
9163 if (!CurrentContext().is_null()) {
9164 CurrentContext()->Print();
9165 if (CurrentContext()->has_extension()) {
9166 Handle<JSObject> extension =
9167 Handle<JSObject>(CurrentContext()->extension());
9168 if (extension->IsJSContextExtensionObject()) {
9169 extension->Print();
9170 }
9171 }
9172 }
9173 break;
9174 }
9175
9176 case ScopeIterator::ScopeTypeWith: {
9177 PrintF("With:\n");
9178 Handle<JSObject> extension =
9179 Handle<JSObject>(CurrentContext()->extension());
9180 extension->Print();
9181 break;
9182 }
9183
ager@chromium.orga1645e22009-09-09 19:27:10 +00009184 case ScopeIterator::ScopeTypeCatch: {
9185 PrintF("Catch:\n");
9186 Handle<JSObject> extension =
9187 Handle<JSObject>(CurrentContext()->extension());
9188 extension->Print();
9189 break;
9190 }
9191
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009192 case ScopeIterator::ScopeTypeClosure: {
9193 PrintF("Closure:\n");
9194 CurrentContext()->Print();
9195 if (CurrentContext()->has_extension()) {
9196 Handle<JSObject> extension =
9197 Handle<JSObject>(CurrentContext()->extension());
9198 if (extension->IsJSContextExtensionObject()) {
9199 extension->Print();
9200 }
9201 }
9202 break;
9203 }
9204
9205 default:
9206 UNREACHABLE();
9207 }
9208 PrintF("\n");
9209 }
9210#endif
9211
9212 private:
9213 JavaScriptFrame* frame_;
9214 Handle<JSFunction> function_;
9215 Handle<Context> context_;
9216 bool local_done_;
9217 bool at_local_;
9218
9219 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
9220};
9221
9222
lrn@chromium.org303ada72010-10-27 09:33:13 +00009223static MaybeObject* Runtime_GetScopeCount(Arguments args) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009224 HandleScope scope;
9225 ASSERT(args.length() == 2);
9226
9227 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009228 Object* check;
9229 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
9230 if (!maybe_check->ToObject(&check)) return maybe_check;
9231 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009232 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
9233
9234 // Get the frame where the debugging is performed.
9235 StackFrame::Id id = UnwrapFrameId(wrapped_id);
9236 JavaScriptFrameIterator it(id);
9237 JavaScriptFrame* frame = it.frame();
9238
9239 // Count the visible scopes.
9240 int n = 0;
9241 for (ScopeIterator it(frame); !it.Done(); it.Next()) {
9242 n++;
9243 }
9244
9245 return Smi::FromInt(n);
9246}
9247
9248
9249static const int kScopeDetailsTypeIndex = 0;
9250static const int kScopeDetailsObjectIndex = 1;
9251static const int kScopeDetailsSize = 2;
9252
9253// Return an array with scope details
9254// args[0]: number: break id
9255// args[1]: number: frame index
9256// args[2]: number: scope index
9257//
9258// The array returned contains the following information:
9259// 0: Scope type
9260// 1: Scope object
lrn@chromium.org303ada72010-10-27 09:33:13 +00009261static MaybeObject* Runtime_GetScopeDetails(Arguments args) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009262 HandleScope scope;
9263 ASSERT(args.length() == 3);
9264
9265 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009266 Object* check;
9267 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
9268 if (!maybe_check->ToObject(&check)) return maybe_check;
9269 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009270 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
9271 CONVERT_NUMBER_CHECKED(int, index, Int32, args[2]);
9272
9273 // Get the frame where the debugging is performed.
9274 StackFrame::Id id = UnwrapFrameId(wrapped_id);
9275 JavaScriptFrameIterator frame_it(id);
9276 JavaScriptFrame* frame = frame_it.frame();
9277
9278 // Find the requested scope.
9279 int n = 0;
9280 ScopeIterator it(frame);
9281 for (; !it.Done() && n < index; it.Next()) {
9282 n++;
9283 }
9284 if (it.Done()) {
9285 return Heap::undefined_value();
9286 }
9287
9288 // Calculate the size of the result.
9289 int details_size = kScopeDetailsSize;
9290 Handle<FixedArray> details = Factory::NewFixedArray(details_size);
9291
9292 // Fill in scope details.
9293 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00009294 Handle<JSObject> scope_object = it.ScopeObject();
9295 details->set(kScopeDetailsObjectIndex, *scope_object);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009296
9297 return *Factory::NewJSArrayWithElements(details);
9298}
9299
9300
lrn@chromium.org303ada72010-10-27 09:33:13 +00009301static MaybeObject* Runtime_DebugPrintScopes(Arguments args) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009302 HandleScope scope;
9303 ASSERT(args.length() == 0);
9304
9305#ifdef DEBUG
9306 // Print the scopes for the top frame.
9307 StackFrameLocator locator;
9308 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
9309 for (ScopeIterator it(frame); !it.Done(); it.Next()) {
9310 it.DebugPrint();
9311 }
9312#endif
9313 return Heap::undefined_value();
9314}
9315
9316
lrn@chromium.org303ada72010-10-27 09:33:13 +00009317static MaybeObject* Runtime_GetThreadCount(Arguments args) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009318 HandleScope scope;
9319 ASSERT(args.length() == 1);
9320
9321 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009322 Object* result;
9323 { MaybeObject* maybe_result = Runtime_CheckExecutionState(args);
9324 if (!maybe_result->ToObject(&result)) return maybe_result;
9325 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009326
9327 // Count all archived V8 threads.
9328 int n = 0;
9329 for (ThreadState* thread = ThreadState::FirstInUse();
9330 thread != NULL;
9331 thread = thread->Next()) {
9332 n++;
9333 }
9334
9335 // Total number of threads is current thread and archived threads.
9336 return Smi::FromInt(n + 1);
9337}
9338
9339
9340static const int kThreadDetailsCurrentThreadIndex = 0;
9341static const int kThreadDetailsThreadIdIndex = 1;
9342static const int kThreadDetailsSize = 2;
9343
9344// Return an array with thread details
9345// args[0]: number: break id
9346// args[1]: number: thread index
9347//
9348// The array returned contains the following information:
9349// 0: Is current thread?
9350// 1: Thread id
lrn@chromium.org303ada72010-10-27 09:33:13 +00009351static MaybeObject* Runtime_GetThreadDetails(Arguments args) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009352 HandleScope scope;
9353 ASSERT(args.length() == 2);
9354
9355 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009356 Object* check;
9357 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
9358 if (!maybe_check->ToObject(&check)) return maybe_check;
9359 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009360 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
9361
9362 // Allocate array for result.
9363 Handle<FixedArray> details = Factory::NewFixedArray(kThreadDetailsSize);
9364
9365 // Thread index 0 is current thread.
9366 if (index == 0) {
9367 // Fill the details.
9368 details->set(kThreadDetailsCurrentThreadIndex, Heap::true_value());
9369 details->set(kThreadDetailsThreadIdIndex,
9370 Smi::FromInt(ThreadManager::CurrentId()));
9371 } else {
9372 // Find the thread with the requested index.
9373 int n = 1;
9374 ThreadState* thread = ThreadState::FirstInUse();
9375 while (index != n && thread != NULL) {
9376 thread = thread->Next();
9377 n++;
9378 }
9379 if (thread == NULL) {
9380 return Heap::undefined_value();
9381 }
9382
9383 // Fill the details.
9384 details->set(kThreadDetailsCurrentThreadIndex, Heap::false_value());
9385 details->set(kThreadDetailsThreadIdIndex, Smi::FromInt(thread->id()));
9386 }
9387
9388 // Convert to JS array and return.
9389 return *Factory::NewJSArrayWithElements(details);
9390}
9391
9392
whesse@chromium.orge90029b2010-08-02 11:52:17 +00009393// Sets the disable break state
9394// args[0]: disable break state
lrn@chromium.org303ada72010-10-27 09:33:13 +00009395static MaybeObject* Runtime_SetDisableBreak(Arguments args) {
whesse@chromium.orge90029b2010-08-02 11:52:17 +00009396 HandleScope scope;
9397 ASSERT(args.length() == 1);
9398 CONVERT_BOOLEAN_CHECKED(disable_break, args[0]);
9399 Debug::set_disable_break(disable_break);
9400 return Heap::undefined_value();
9401}
9402
9403
lrn@chromium.org303ada72010-10-27 09:33:13 +00009404static MaybeObject* Runtime_GetBreakLocations(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009405 HandleScope scope;
9406 ASSERT(args.length() == 1);
9407
ager@chromium.org5aa501c2009-06-23 07:57:28 +00009408 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
9409 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009410 // Find the number of break points
9411 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
9412 if (break_locations->IsUndefined()) return Heap::undefined_value();
9413 // Return array as JS array
9414 return *Factory::NewJSArrayWithElements(
9415 Handle<FixedArray>::cast(break_locations));
9416}
9417
9418
9419// Set a break point in a function
9420// args[0]: function
9421// args[1]: number: break source position (within the function source)
9422// args[2]: number: break point object
lrn@chromium.org303ada72010-10-27 09:33:13 +00009423static MaybeObject* Runtime_SetFunctionBreakPoint(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009424 HandleScope scope;
9425 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00009426 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
9427 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009428 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
9429 RUNTIME_ASSERT(source_position >= 0);
9430 Handle<Object> break_point_object_arg = args.at<Object>(2);
9431
9432 // Set break point.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00009433 Debug::SetBreakPoint(shared, break_point_object_arg, &source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009434
lrn@chromium.org32d961d2010-06-30 09:09:34 +00009435 return Smi::FromInt(source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009436}
9437
9438
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00009439Object* Runtime::FindSharedFunctionInfoInScript(Handle<Script> script,
9440 int position) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009441 // Iterate the heap looking for SharedFunctionInfo generated from the
9442 // script. The inner most SharedFunctionInfo containing the source position
9443 // for the requested break point is found.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009444 // NOTE: This might require several heap iterations. If the SharedFunctionInfo
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009445 // which is found is not compiled it is compiled and the heap is iterated
9446 // again as the compilation might create inner functions from the newly
9447 // compiled function and the actual requested break point might be in one of
9448 // these functions.
9449 bool done = false;
9450 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +00009451 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009452 Handle<SharedFunctionInfo> target;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009453 while (!done) {
9454 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009455 for (HeapObject* obj = iterator.next();
9456 obj != NULL; obj = iterator.next()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009457 if (obj->IsSharedFunctionInfo()) {
9458 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
9459 if (shared->script() == *script) {
9460 // If the SharedFunctionInfo found has the requested script data and
9461 // contains the source position it is a candidate.
9462 int start_position = shared->function_token_position();
ager@chromium.org236ad962008-09-25 09:45:57 +00009463 if (start_position == RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009464 start_position = shared->start_position();
9465 }
9466 if (start_position <= position &&
9467 position <= shared->end_position()) {
ager@chromium.org32912102009-01-16 10:38:43 +00009468 // If there is no candidate or this function is within the current
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009469 // candidate this is the new candidate.
9470 if (target.is_null()) {
9471 target_start_position = start_position;
9472 target = shared;
9473 } else {
ager@chromium.orga1645e22009-09-09 19:27:10 +00009474 if (target_start_position == start_position &&
9475 shared->end_position() == target->end_position()) {
9476 // If a top-level function contain only one function
9477 // declartion the source for the top-level and the function is
9478 // the same. In that case prefer the non top-level function.
9479 if (!shared->is_toplevel()) {
9480 target_start_position = start_position;
9481 target = shared;
9482 }
9483 } else if (target_start_position <= start_position &&
9484 shared->end_position() <= target->end_position()) {
9485 // This containment check includes equality as a function inside
9486 // a top-level function can share either start or end position
9487 // with the top-level function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009488 target_start_position = start_position;
9489 target = shared;
9490 }
9491 }
9492 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009493 }
9494 }
9495 }
9496
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009497 if (target.is_null()) {
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00009498 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009499 }
9500
9501 // If the candidate found is compiled we are done. NOTE: when lazy
9502 // compilation of inner functions is introduced some additional checking
9503 // needs to be done here to compile inner functions.
9504 done = target->is_compiled();
9505 if (!done) {
9506 // If the candidate is not compiled compile it to reveal any inner
9507 // functions which might contain the requested source position.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009508 CompileLazyShared(target, KEEP_EXCEPTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009509 }
9510 }
9511
9512 return *target;
9513}
9514
9515
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00009516// Changes the state of a break point in a script and returns source position
9517// where break point was set. NOTE: Regarding performance see the NOTE for
9518// GetScriptFromScriptData.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009519// args[0]: script to set break point in
9520// args[1]: number: break source position (within the script source)
9521// args[2]: number: break point object
lrn@chromium.org303ada72010-10-27 09:33:13 +00009522static MaybeObject* Runtime_SetScriptBreakPoint(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009523 HandleScope scope;
9524 ASSERT(args.length() == 3);
9525 CONVERT_ARG_CHECKED(JSValue, wrapper, 0);
9526 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
9527 RUNTIME_ASSERT(source_position >= 0);
9528 Handle<Object> break_point_object_arg = args.at<Object>(2);
9529
9530 // Get the script from the script wrapper.
9531 RUNTIME_ASSERT(wrapper->value()->IsScript());
9532 Handle<Script> script(Script::cast(wrapper->value()));
9533
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00009534 Object* result = Runtime::FindSharedFunctionInfoInScript(
9535 script, source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009536 if (!result->IsUndefined()) {
9537 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
9538 // Find position within function. The script position might be before the
9539 // source position of the first function.
9540 int position;
9541 if (shared->start_position() > source_position) {
9542 position = 0;
9543 } else {
9544 position = source_position - shared->start_position();
9545 }
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00009546 Debug::SetBreakPoint(shared, break_point_object_arg, &position);
9547 position += shared->start_position();
9548 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009549 }
9550 return Heap::undefined_value();
9551}
9552
9553
9554// Clear a break point
9555// args[0]: number: break point object
lrn@chromium.org303ada72010-10-27 09:33:13 +00009556static MaybeObject* Runtime_ClearBreakPoint(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009557 HandleScope scope;
9558 ASSERT(args.length() == 1);
9559 Handle<Object> break_point_object_arg = args.at<Object>(0);
9560
9561 // Clear break point.
9562 Debug::ClearBreakPoint(break_point_object_arg);
9563
9564 return Heap::undefined_value();
9565}
9566
9567
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00009568// Change the state of break on exceptions.
9569// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
9570// args[1]: Boolean indicating on/off.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009571static MaybeObject* Runtime_ChangeBreakOnException(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009572 HandleScope scope;
9573 ASSERT(args.length() == 2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00009574 RUNTIME_ASSERT(args[0]->IsNumber());
9575 CONVERT_BOOLEAN_CHECKED(enable, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009576
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00009577 // If the number doesn't match an enum value, the ChangeBreakOnException
9578 // function will default to affecting caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009579 ExceptionBreakType type =
9580 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00009581 // Update break point state.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009582 Debug::ChangeBreakOnException(type, enable);
9583 return Heap::undefined_value();
9584}
9585
9586
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00009587// Returns the state of break on exceptions
9588// args[0]: boolean indicating uncaught exceptions
lrn@chromium.org303ada72010-10-27 09:33:13 +00009589static MaybeObject* Runtime_IsBreakOnException(Arguments args) {
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00009590 HandleScope scope;
9591 ASSERT(args.length() == 1);
9592 RUNTIME_ASSERT(args[0]->IsNumber());
9593
9594 ExceptionBreakType type =
9595 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
9596 bool result = Debug::IsBreakOnException(type);
9597 return Smi::FromInt(result);
9598}
9599
9600
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009601// Prepare for stepping
9602// args[0]: break id for checking execution state
9603// args[1]: step action from the enumeration StepAction
ager@chromium.orga1645e22009-09-09 19:27:10 +00009604// args[2]: number of times to perform the step, for step out it is the number
9605// of frames to step down.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009606static MaybeObject* Runtime_PrepareStep(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009607 HandleScope scope;
9608 ASSERT(args.length() == 3);
9609 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009610 Object* check;
9611 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
9612 if (!maybe_check->ToObject(&check)) return maybe_check;
9613 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009614 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
9615 return Top::Throw(Heap::illegal_argument_symbol());
9616 }
9617
9618 // Get the step action and check validity.
9619 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
9620 if (step_action != StepIn &&
9621 step_action != StepNext &&
9622 step_action != StepOut &&
9623 step_action != StepInMin &&
9624 step_action != StepMin) {
9625 return Top::Throw(Heap::illegal_argument_symbol());
9626 }
9627
9628 // Get the number of steps.
9629 int step_count = NumberToInt32(args[2]);
9630 if (step_count < 1) {
9631 return Top::Throw(Heap::illegal_argument_symbol());
9632 }
9633
ager@chromium.orga1645e22009-09-09 19:27:10 +00009634 // Clear all current stepping setup.
9635 Debug::ClearStepping();
9636
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009637 // Prepare step.
9638 Debug::PrepareStep(static_cast<StepAction>(step_action), step_count);
9639 return Heap::undefined_value();
9640}
9641
9642
9643// Clear all stepping set by PrepareStep.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009644static MaybeObject* Runtime_ClearStepping(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009645 HandleScope scope;
mads.s.ager31e71382008-08-13 09:32:07 +00009646 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009647 Debug::ClearStepping();
9648 return Heap::undefined_value();
9649}
9650
9651
9652// Creates a copy of the with context chain. The copy of the context chain is
9653// is linked to the function context supplied.
9654static Handle<Context> CopyWithContextChain(Handle<Context> context_chain,
9655 Handle<Context> function_context) {
9656 // At the bottom of the chain. Return the function context to link to.
9657 if (context_chain->is_function_context()) {
9658 return function_context;
9659 }
9660
9661 // Recursively copy the with contexts.
9662 Handle<Context> previous(context_chain->previous());
9663 Handle<JSObject> extension(JSObject::cast(context_chain->extension()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00009664 Handle<Context> context = CopyWithContextChain(function_context, previous);
9665 return Factory::NewWithContext(context,
9666 extension,
9667 context_chain->IsCatchContext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009668}
9669
9670
9671// Helper function to find or create the arguments object for
9672// Runtime_DebugEvaluate.
9673static Handle<Object> GetArgumentsObject(JavaScriptFrame* frame,
9674 Handle<JSFunction> function,
ager@chromium.orgb5737492010-07-15 09:29:43 +00009675 Handle<SerializedScopeInfo> scope_info,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009676 const ScopeInfo<>* sinfo,
9677 Handle<Context> function_context) {
9678 // Try to find the value of 'arguments' to pass as parameter. If it is not
9679 // found (that is the debugged function does not reference 'arguments' and
9680 // does not support eval) then create an 'arguments' object.
9681 int index;
9682 if (sinfo->number_of_stack_slots() > 0) {
ager@chromium.orgb5737492010-07-15 09:29:43 +00009683 index = scope_info->StackSlotIndex(Heap::arguments_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009684 if (index != -1) {
9685 return Handle<Object>(frame->GetExpression(index));
9686 }
9687 }
9688
9689 if (sinfo->number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
ager@chromium.orgb5737492010-07-15 09:29:43 +00009690 index = scope_info->ContextSlotIndex(Heap::arguments_symbol(), NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009691 if (index != -1) {
9692 return Handle<Object>(function_context->get(index));
9693 }
9694 }
9695
9696 const int length = frame->GetProvidedParametersCount();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009697 Handle<JSObject> arguments = Factory::NewArgumentsObject(function, length);
9698 Handle<FixedArray> array = Factory::NewFixedArray(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009699
9700 AssertNoAllocation no_gc;
9701 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009702 for (int i = 0; i < length; i++) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009703 array->set(i, frame->GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009704 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009705 arguments->set_elements(*array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009706 return arguments;
9707}
9708
9709
9710// Evaluate a piece of JavaScript in the context of a stack frame for
ager@chromium.org32912102009-01-16 10:38:43 +00009711// debugging. This is accomplished by creating a new context which in its
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009712// extension part has all the parameters and locals of the function on the
9713// stack frame. A function which calls eval with the code to evaluate is then
9714// compiled in this context and called in this context. As this context
9715// replaces the context of the function on the stack frame a new (empty)
9716// function is created as well to be used as the closure for the context.
9717// This function and the context acts as replacements for the function on the
9718// stack frame presenting the same view of the values of parameters and
9719// local variables as if the piece of JavaScript was evaluated at the point
9720// where the function on the stack frame is currently stopped.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009721static MaybeObject* Runtime_DebugEvaluate(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009722 HandleScope scope;
9723
9724 // Check the execution state and decode arguments frame and source to be
9725 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009726 ASSERT(args.length() == 5);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009727 Object* check_result;
9728 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(args);
9729 if (!maybe_check_result->ToObject(&check_result)) {
9730 return maybe_check_result;
9731 }
9732 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009733 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
9734 CONVERT_ARG_CHECKED(String, source, 2);
kasper.lundbd3ec4e2008-07-09 11:06:54 +00009735 CONVERT_BOOLEAN_CHECKED(disable_break, args[3]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009736 Handle<Object> additional_context(args[4]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +00009737
9738 // Handle the processing of break.
9739 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009740
9741 // Get the frame where the debugging is performed.
9742 StackFrame::Id id = UnwrapFrameId(wrapped_id);
9743 JavaScriptFrameIterator it(id);
9744 JavaScriptFrame* frame = it.frame();
9745 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +00009746 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009747 ScopeInfo<> sinfo(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009748
9749 // Traverse the saved contexts chain to find the active context for the
9750 // selected frame.
9751 SaveContext* save = Top::save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009752 while (save != NULL && !save->below(frame)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009753 save = save->prev();
9754 }
9755 ASSERT(save != NULL);
9756 SaveContext savex;
9757 Top::set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009758
9759 // Create the (empty) function replacing the function on the stack frame for
9760 // the purpose of evaluating in the context created below. It is important
9761 // that this function does not describe any parameters and local variables
9762 // in the context. If it does then this will cause problems with the lookup
9763 // in Context::Lookup, where context slots for parameters and local variables
9764 // are looked at before the extension object.
9765 Handle<JSFunction> go_between =
9766 Factory::NewFunction(Factory::empty_string(), Factory::undefined_value());
9767 go_between->set_context(function->context());
9768#ifdef DEBUG
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009769 ScopeInfo<> go_between_sinfo(go_between->shared()->scope_info());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009770 ASSERT(go_between_sinfo.number_of_parameters() == 0);
9771 ASSERT(go_between_sinfo.number_of_context_slots() == 0);
9772#endif
9773
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009774 // Materialize the content of the local scope into a JSObject.
9775 Handle<JSObject> local_scope = MaterializeLocalScope(frame);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009776
9777 // Allocate a new context for the debug evaluation and set the extension
9778 // object build.
9779 Handle<Context> context =
9780 Factory::NewFunctionContext(Context::MIN_CONTEXT_SLOTS, go_between);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009781 context->set_extension(*local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009782 // Copy any with contexts present and chain them in front of this context.
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009783 Handle<Context> frame_context(Context::cast(frame->context()));
9784 Handle<Context> function_context(frame_context->fcontext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009785 context = CopyWithContextChain(frame_context, context);
9786
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009787 if (additional_context->IsJSObject()) {
9788 context = Factory::NewWithContext(context,
9789 Handle<JSObject>::cast(additional_context), false);
9790 }
9791
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009792 // Wrap the evaluation statement in a new function compiled in the newly
9793 // created context. The function has one parameter which has to be called
9794 // 'arguments'. This it to have access to what would have been 'arguments' in
ager@chromium.org32912102009-01-16 10:38:43 +00009795 // the function being debugged.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009796 // function(arguments,__source__) {return eval(__source__);}
9797 static const char* source_str =
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00009798 "(function(arguments,__source__){return eval(__source__);})";
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009799 static const int source_str_length = StrLength(source_str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009800 Handle<String> function_source =
9801 Factory::NewStringFromAscii(Vector<const char>(source_str,
9802 source_str_length));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009803 Handle<SharedFunctionInfo> shared =
ager@chromium.org381abbb2009-02-25 13:23:22 +00009804 Compiler::CompileEval(function_source,
9805 context,
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009806 context->IsGlobalContext());
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009807 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009808 Handle<JSFunction> compiled_function =
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009809 Factory::NewFunctionFromSharedFunctionInfo(shared, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009810
9811 // Invoke the result of the compilation to get the evaluation function.
9812 bool has_pending_exception;
9813 Handle<Object> receiver(frame->receiver());
9814 Handle<Object> evaluation_function =
9815 Execution::Call(compiled_function, receiver, 0, NULL,
9816 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00009817 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009818
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009819 Handle<Object> arguments = GetArgumentsObject(frame, function, scope_info,
9820 &sinfo, function_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009821
9822 // Invoke the evaluation function and return the result.
9823 const int argc = 2;
9824 Object** argv[argc] = { arguments.location(),
9825 Handle<Object>::cast(source).location() };
9826 Handle<Object> result =
9827 Execution::Call(Handle<JSFunction>::cast(evaluation_function), receiver,
9828 argc, argv, &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00009829 if (has_pending_exception) return Failure::Exception();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009830
9831 // Skip the global proxy as it has no properties and always delegates to the
9832 // real global object.
9833 if (result->IsJSGlobalProxy()) {
9834 result = Handle<JSObject>(JSObject::cast(result->GetPrototype()));
9835 }
9836
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009837 return *result;
9838}
9839
9840
lrn@chromium.org303ada72010-10-27 09:33:13 +00009841static MaybeObject* Runtime_DebugEvaluateGlobal(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009842 HandleScope scope;
9843
9844 // Check the execution state and decode arguments frame and source to be
9845 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009846 ASSERT(args.length() == 4);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009847 Object* check_result;
9848 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(args);
9849 if (!maybe_check_result->ToObject(&check_result)) {
9850 return maybe_check_result;
9851 }
9852 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009853 CONVERT_ARG_CHECKED(String, source, 1);
kasper.lundbd3ec4e2008-07-09 11:06:54 +00009854 CONVERT_BOOLEAN_CHECKED(disable_break, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009855 Handle<Object> additional_context(args[3]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +00009856
9857 // Handle the processing of break.
9858 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009859
9860 // Enter the top context from before the debugger was invoked.
9861 SaveContext save;
9862 SaveContext* top = &save;
9863 while (top != NULL && *top->context() == *Debug::debug_context()) {
9864 top = top->prev();
9865 }
9866 if (top != NULL) {
9867 Top::set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009868 }
9869
9870 // Get the global context now set to the top context from before the
9871 // debugger was invoked.
9872 Handle<Context> context = Top::global_context();
9873
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009874 bool is_global = true;
9875
9876 if (additional_context->IsJSObject()) {
9877 // Create a function context first, than put 'with' context on top of it.
9878 Handle<JSFunction> go_between = Factory::NewFunction(
9879 Factory::empty_string(), Factory::undefined_value());
9880 go_between->set_context(*context);
9881 context =
9882 Factory::NewFunctionContext(Context::MIN_CONTEXT_SLOTS, go_between);
9883 context->set_extension(JSObject::cast(*additional_context));
9884 is_global = false;
9885 }
9886
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009887 // Compile the source to be evaluated.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009888 Handle<SharedFunctionInfo> shared =
9889 Compiler::CompileEval(source,
9890 context,
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009891 is_global);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009892 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009893 Handle<JSFunction> compiled_function =
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009894 Handle<JSFunction>(Factory::NewFunctionFromSharedFunctionInfo(shared,
9895 context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009896
9897 // Invoke the result of the compilation to get the evaluation function.
9898 bool has_pending_exception;
9899 Handle<Object> receiver = Top::global();
9900 Handle<Object> result =
9901 Execution::Call(compiled_function, receiver, 0, NULL,
9902 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00009903 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009904 return *result;
9905}
9906
9907
lrn@chromium.org303ada72010-10-27 09:33:13 +00009908static MaybeObject* Runtime_DebugGetLoadedScripts(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009909 HandleScope scope;
mads.s.ager31e71382008-08-13 09:32:07 +00009910 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009911
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009912 // Fill the script objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +00009913 Handle<FixedArray> instances = Debug::GetLoadedScripts();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009914
9915 // Convert the script objects to proper JS objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +00009916 for (int i = 0; i < instances->length(); i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00009917 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
9918 // Get the script wrapper in a local handle before calling GetScriptWrapper,
9919 // because using
9920 // instances->set(i, *GetScriptWrapper(script))
9921 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
9922 // already have deferenced the instances handle.
9923 Handle<JSValue> wrapper = GetScriptWrapper(script);
9924 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009925 }
9926
9927 // Return result as a JS array.
9928 Handle<JSObject> result = Factory::NewJSObject(Top::array_function());
9929 Handle<JSArray>::cast(result)->SetContent(*instances);
9930 return *result;
9931}
9932
9933
9934// Helper function used by Runtime_DebugReferencedBy below.
9935static int DebugReferencedBy(JSObject* target,
9936 Object* instance_filter, int max_references,
9937 FixedArray* instances, int instances_size,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009938 JSFunction* arguments_function) {
9939 NoHandleAllocation ha;
9940 AssertNoAllocation no_alloc;
9941
9942 // Iterate the heap.
9943 int count = 0;
9944 JSObject* last = NULL;
9945 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009946 HeapObject* heap_obj = NULL;
9947 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009948 (max_references == 0 || count < max_references)) {
9949 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009950 if (heap_obj->IsJSObject()) {
9951 // Skip context extension objects and argument arrays as these are
9952 // checked in the context of functions using them.
9953 JSObject* obj = JSObject::cast(heap_obj);
iposva@chromium.org245aa852009-02-10 00:49:54 +00009954 if (obj->IsJSContextExtensionObject() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009955 obj->map()->constructor() == arguments_function) {
9956 continue;
9957 }
9958
9959 // Check if the JS object has a reference to the object looked for.
9960 if (obj->ReferencesObject(target)) {
9961 // Check instance filter if supplied. This is normally used to avoid
9962 // references from mirror objects (see Runtime_IsInPrototypeChain).
9963 if (!instance_filter->IsUndefined()) {
9964 Object* V = obj;
9965 while (true) {
9966 Object* prototype = V->GetPrototype();
9967 if (prototype->IsNull()) {
9968 break;
9969 }
9970 if (instance_filter == prototype) {
9971 obj = NULL; // Don't add this object.
9972 break;
9973 }
9974 V = prototype;
9975 }
9976 }
9977
9978 if (obj != NULL) {
9979 // Valid reference found add to instance array if supplied an update
9980 // count.
9981 if (instances != NULL && count < instances_size) {
9982 instances->set(count, obj);
9983 }
9984 last = obj;
9985 count++;
9986 }
9987 }
9988 }
9989 }
9990
9991 // Check for circular reference only. This can happen when the object is only
9992 // referenced from mirrors and has a circular reference in which case the
9993 // object is not really alive and would have been garbage collected if not
9994 // referenced from the mirror.
9995 if (count == 1 && last == target) {
9996 count = 0;
9997 }
9998
9999 // Return the number of referencing objects found.
10000 return count;
10001}
10002
10003
10004// Scan the heap for objects with direct references to an object
10005// args[0]: the object to find references to
10006// args[1]: constructor function for instances to exclude (Mirror)
10007// args[2]: the the maximum number of objects to return
lrn@chromium.org303ada72010-10-27 09:33:13 +000010008static MaybeObject* Runtime_DebugReferencedBy(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010009 ASSERT(args.length() == 3);
10010
10011 // First perform a full GC in order to avoid references from dead objects.
ager@chromium.orgab99eea2009-08-25 07:05:41 +000010012 Heap::CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010013
10014 // Check parameters.
10015 CONVERT_CHECKED(JSObject, target, args[0]);
10016 Object* instance_filter = args[1];
10017 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
10018 instance_filter->IsJSObject());
10019 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
10020 RUNTIME_ASSERT(max_references >= 0);
10021
10022 // Get the constructor function for context extension and arguments array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010023 JSObject* arguments_boilerplate =
10024 Top::context()->global_context()->arguments_boilerplate();
10025 JSFunction* arguments_function =
10026 JSFunction::cast(arguments_boilerplate->map()->constructor());
10027
10028 // Get the number of referencing objects.
10029 int count;
10030 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000010031 NULL, 0, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010032
10033 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010034 Object* object;
10035 { MaybeObject* maybe_object = Heap::AllocateFixedArray(count);
10036 if (!maybe_object->ToObject(&object)) return maybe_object;
10037 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010038 FixedArray* instances = FixedArray::cast(object);
10039
10040 // Fill the referencing objects.
10041 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000010042 instances, count, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010043
10044 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010045 Object* result;
10046 { MaybeObject* maybe_result = Heap::AllocateJSObject(
10047 Top::context()->global_context()->array_function());
10048 if (!maybe_result->ToObject(&result)) return maybe_result;
10049 }
10050 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010051 return result;
10052}
10053
10054
10055// Helper function used by Runtime_DebugConstructedBy below.
10056static int DebugConstructedBy(JSFunction* constructor, int max_references,
10057 FixedArray* instances, int instances_size) {
10058 AssertNoAllocation no_alloc;
10059
10060 // Iterate the heap.
10061 int count = 0;
10062 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010063 HeapObject* heap_obj = NULL;
10064 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010065 (max_references == 0 || count < max_references)) {
10066 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010067 if (heap_obj->IsJSObject()) {
10068 JSObject* obj = JSObject::cast(heap_obj);
10069 if (obj->map()->constructor() == constructor) {
10070 // Valid reference found add to instance array if supplied an update
10071 // count.
10072 if (instances != NULL && count < instances_size) {
10073 instances->set(count, obj);
10074 }
10075 count++;
10076 }
10077 }
10078 }
10079
10080 // Return the number of referencing objects found.
10081 return count;
10082}
10083
10084
10085// Scan the heap for objects constructed by a specific function.
10086// args[0]: the constructor to find instances of
10087// args[1]: the the maximum number of objects to return
lrn@chromium.org303ada72010-10-27 09:33:13 +000010088static MaybeObject* Runtime_DebugConstructedBy(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010089 ASSERT(args.length() == 2);
10090
10091 // First perform a full GC in order to avoid dead objects.
ager@chromium.orgab99eea2009-08-25 07:05:41 +000010092 Heap::CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010093
10094 // Check parameters.
10095 CONVERT_CHECKED(JSFunction, constructor, args[0]);
10096 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
10097 RUNTIME_ASSERT(max_references >= 0);
10098
10099 // Get the number of referencing objects.
10100 int count;
10101 count = DebugConstructedBy(constructor, max_references, NULL, 0);
10102
10103 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010104 Object* object;
10105 { MaybeObject* maybe_object = Heap::AllocateFixedArray(count);
10106 if (!maybe_object->ToObject(&object)) return maybe_object;
10107 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010108 FixedArray* instances = FixedArray::cast(object);
10109
10110 // Fill the referencing objects.
10111 count = DebugConstructedBy(constructor, max_references, instances, count);
10112
10113 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010114 Object* result;
10115 { MaybeObject* maybe_result = Heap::AllocateJSObject(
10116 Top::context()->global_context()->array_function());
10117 if (!maybe_result->ToObject(&result)) return maybe_result;
10118 }
10119 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010120 return result;
10121}
10122
10123
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010124// Find the effective prototype object as returned by __proto__.
10125// args[0]: the object to find the prototype for.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010126static MaybeObject* Runtime_DebugGetPrototype(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010127 ASSERT(args.length() == 1);
10128
10129 CONVERT_CHECKED(JSObject, obj, args[0]);
10130
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010131 // Use the __proto__ accessor.
10132 return Accessors::ObjectPrototype.getter(obj, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010133}
10134
10135
lrn@chromium.org303ada72010-10-27 09:33:13 +000010136static MaybeObject* Runtime_SystemBreak(Arguments args) {
mads.s.ager31e71382008-08-13 09:32:07 +000010137 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010138 CPU::DebugBreak();
10139 return Heap::undefined_value();
10140}
10141
10142
lrn@chromium.org303ada72010-10-27 09:33:13 +000010143static MaybeObject* Runtime_DebugDisassembleFunction(Arguments args) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010144#ifdef DEBUG
10145 HandleScope scope;
10146 ASSERT(args.length() == 1);
10147 // Get the function and make sure it is compiled.
10148 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010149 Handle<SharedFunctionInfo> shared(func->shared());
10150 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010151 return Failure::Exception();
10152 }
10153 func->code()->PrintLn();
10154#endif // DEBUG
10155 return Heap::undefined_value();
10156}
ager@chromium.org9085a012009-05-11 19:22:57 +000010157
10158
lrn@chromium.org303ada72010-10-27 09:33:13 +000010159static MaybeObject* Runtime_DebugDisassembleConstructor(Arguments args) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000010160#ifdef DEBUG
10161 HandleScope scope;
10162 ASSERT(args.length() == 1);
10163 // Get the function and make sure it is compiled.
10164 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010165 Handle<SharedFunctionInfo> shared(func->shared());
10166 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000010167 return Failure::Exception();
10168 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010169 shared->construct_stub()->PrintLn();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000010170#endif // DEBUG
10171 return Heap::undefined_value();
10172}
10173
10174
lrn@chromium.org303ada72010-10-27 09:33:13 +000010175static MaybeObject* Runtime_FunctionGetInferredName(Arguments args) {
ager@chromium.org9085a012009-05-11 19:22:57 +000010176 NoHandleAllocation ha;
10177 ASSERT(args.length() == 1);
10178
10179 CONVERT_CHECKED(JSFunction, f, args[0]);
10180 return f->shared()->inferred_name();
10181}
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010182
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010183
10184static int FindSharedFunctionInfosForScript(Script* script,
10185 FixedArray* buffer) {
10186 AssertNoAllocation no_allocations;
10187
10188 int counter = 0;
10189 int buffer_size = buffer->length();
10190 HeapIterator iterator;
10191 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
10192 ASSERT(obj != NULL);
10193 if (!obj->IsSharedFunctionInfo()) {
10194 continue;
10195 }
10196 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
10197 if (shared->script() != script) {
10198 continue;
10199 }
10200 if (counter < buffer_size) {
10201 buffer->set(counter, shared);
10202 }
10203 counter++;
10204 }
10205 return counter;
10206}
10207
10208// For a script finds all SharedFunctionInfo's in the heap that points
10209// to this script. Returns JSArray of SharedFunctionInfo wrapped
10210// in OpaqueReferences.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010211static MaybeObject* Runtime_LiveEditFindSharedFunctionInfosForScript(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010212 Arguments args) {
10213 ASSERT(args.length() == 1);
10214 HandleScope scope;
10215 CONVERT_CHECKED(JSValue, script_value, args[0]);
10216
10217 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
10218
10219 const int kBufferSize = 32;
10220
10221 Handle<FixedArray> array;
10222 array = Factory::NewFixedArray(kBufferSize);
10223 int number = FindSharedFunctionInfosForScript(*script, *array);
10224 if (number > kBufferSize) {
10225 array = Factory::NewFixedArray(number);
10226 FindSharedFunctionInfosForScript(*script, *array);
10227 }
10228
10229 Handle<JSArray> result = Factory::NewJSArrayWithElements(array);
10230 result->set_length(Smi::FromInt(number));
10231
10232 LiveEdit::WrapSharedFunctionInfos(result);
10233
10234 return *result;
10235}
10236
10237// For a script calculates compilation information about all its functions.
10238// The script source is explicitly specified by the second argument.
10239// The source of the actual script is not used, however it is important that
10240// all generated code keeps references to this particular instance of script.
10241// Returns a JSArray of compilation infos. The array is ordered so that
10242// each function with all its descendant is always stored in a continues range
10243// with the function itself going first. The root function is a script function.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010244static MaybeObject* Runtime_LiveEditGatherCompileInfo(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010245 ASSERT(args.length() == 2);
10246 HandleScope scope;
10247 CONVERT_CHECKED(JSValue, script, args[0]);
10248 CONVERT_ARG_CHECKED(String, source, 1);
10249 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
10250
10251 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
10252
10253 if (Top::has_pending_exception()) {
10254 return Failure::Exception();
10255 }
10256
10257 return result;
10258}
10259
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010260// Changes the source of the script to a new_source.
10261// If old_script_name is provided (i.e. is a String), also creates a copy of
10262// the script with its original source and sends notification to debugger.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010263static MaybeObject* Runtime_LiveEditReplaceScript(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010264 ASSERT(args.length() == 3);
10265 HandleScope scope;
10266 CONVERT_CHECKED(JSValue, original_script_value, args[0]);
10267 CONVERT_ARG_CHECKED(String, new_source, 1);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010268 Handle<Object> old_script_name(args[2]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010269
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010270 CONVERT_CHECKED(Script, original_script_pointer,
10271 original_script_value->value());
10272 Handle<Script> original_script(original_script_pointer);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010273
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010274 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
10275 new_source,
10276 old_script_name);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010277
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010278 if (old_script->IsScript()) {
10279 Handle<Script> script_handle(Script::cast(old_script));
10280 return *(GetScriptWrapper(script_handle));
10281 } else {
10282 return Heap::null_value();
10283 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010284}
10285
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010286
10287static MaybeObject* Runtime_LiveEditFunctionSourceUpdated(Arguments args) {
10288 ASSERT(args.length() == 1);
10289 HandleScope scope;
10290 CONVERT_ARG_CHECKED(JSArray, shared_info, 0);
10291 return LiveEdit::FunctionSourceUpdated(shared_info);
10292}
10293
10294
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010295// Replaces code of SharedFunctionInfo with a new one.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010296static MaybeObject* Runtime_LiveEditReplaceFunctionCode(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010297 ASSERT(args.length() == 2);
10298 HandleScope scope;
10299 CONVERT_ARG_CHECKED(JSArray, new_compile_info, 0);
10300 CONVERT_ARG_CHECKED(JSArray, shared_info, 1);
10301
ager@chromium.orgac091b72010-05-05 07:34:42 +000010302 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010303}
10304
10305// Connects SharedFunctionInfo to another script.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010306static MaybeObject* Runtime_LiveEditFunctionSetScript(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010307 ASSERT(args.length() == 2);
10308 HandleScope scope;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010309 Handle<Object> function_object(args[0]);
10310 Handle<Object> script_object(args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010311
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010312 if (function_object->IsJSValue()) {
10313 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
10314 if (script_object->IsJSValue()) {
10315 CONVERT_CHECKED(Script, script, JSValue::cast(*script_object)->value());
10316 script_object = Handle<Object>(script);
10317 }
10318
10319 LiveEdit::SetFunctionScript(function_wrapper, script_object);
10320 } else {
10321 // Just ignore this. We may not have a SharedFunctionInfo for some functions
10322 // and we check it in this function.
10323 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010324
10325 return Heap::undefined_value();
10326}
10327
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010328
10329// In a code of a parent function replaces original function as embedded object
10330// with a substitution one.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010331static MaybeObject* Runtime_LiveEditReplaceRefToNestedFunction(Arguments args) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010332 ASSERT(args.length() == 3);
10333 HandleScope scope;
10334
10335 CONVERT_ARG_CHECKED(JSValue, parent_wrapper, 0);
10336 CONVERT_ARG_CHECKED(JSValue, orig_wrapper, 1);
10337 CONVERT_ARG_CHECKED(JSValue, subst_wrapper, 2);
10338
10339 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
10340 subst_wrapper);
10341
10342 return Heap::undefined_value();
10343}
10344
10345
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010346// Updates positions of a shared function info (first parameter) according
10347// to script source change. Text change is described in second parameter as
10348// array of groups of 3 numbers:
10349// (change_begin, change_end, change_end_new_position).
10350// Each group describes a change in text; groups are sorted by change_begin.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010351static MaybeObject* Runtime_LiveEditPatchFunctionPositions(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010352 ASSERT(args.length() == 2);
10353 HandleScope scope;
10354 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
10355 CONVERT_ARG_CHECKED(JSArray, position_change_array, 1);
10356
ager@chromium.orgac091b72010-05-05 07:34:42 +000010357 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010358}
10359
10360
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010361// For array of SharedFunctionInfo's (each wrapped in JSValue)
10362// checks that none of them have activations on stacks (of any thread).
10363// Returns array of the same length with corresponding results of
10364// LiveEdit::FunctionPatchabilityStatus type.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010365static MaybeObject* Runtime_LiveEditCheckAndDropActivations(Arguments args) {
ager@chromium.org357bf652010-04-12 11:30:10 +000010366 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010367 HandleScope scope;
10368 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
ager@chromium.org357bf652010-04-12 11:30:10 +000010369 CONVERT_BOOLEAN_CHECKED(do_drop, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010370
ager@chromium.org357bf652010-04-12 11:30:10 +000010371 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010372}
10373
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000010374// Compares 2 strings line-by-line, then token-wise and returns diff in form
10375// of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
10376// of diff chunks.
10377static MaybeObject* Runtime_LiveEditCompareStrings(Arguments args) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010378 ASSERT(args.length() == 2);
10379 HandleScope scope;
10380 CONVERT_ARG_CHECKED(String, s1, 0);
10381 CONVERT_ARG_CHECKED(String, s2, 1);
10382
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000010383 return *LiveEdit::CompareStrings(s1, s2);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010384}
10385
10386
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010387
fschneider@chromium.org086aac62010-03-17 13:18:24 +000010388// A testing entry. Returns statement position which is the closest to
10389// source_position.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010390static MaybeObject* Runtime_GetFunctionCodePositionFromSource(Arguments args) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +000010391 ASSERT(args.length() == 2);
10392 HandleScope scope;
10393 CONVERT_ARG_CHECKED(JSFunction, function, 0);
10394 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
10395
10396 Handle<Code> code(function->code());
10397
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010398 if (code->kind() != Code::FUNCTION &&
10399 code->kind() != Code::OPTIMIZED_FUNCTION) {
10400 return Heap::undefined_value();
10401 }
10402
10403 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
fschneider@chromium.org086aac62010-03-17 13:18:24 +000010404 int closest_pc = 0;
10405 int distance = kMaxInt;
10406 while (!it.done()) {
10407 int statement_position = static_cast<int>(it.rinfo()->data());
10408 // Check if this break point is closer that what was previously found.
10409 if (source_position <= statement_position &&
10410 statement_position - source_position < distance) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +000010411 closest_pc =
10412 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
fschneider@chromium.org086aac62010-03-17 13:18:24 +000010413 distance = statement_position - source_position;
10414 // Check whether we can't get any closer.
10415 if (distance == 0) break;
10416 }
10417 it.next();
10418 }
10419
10420 return Smi::FromInt(closest_pc);
10421}
10422
10423
ager@chromium.org357bf652010-04-12 11:30:10 +000010424// Calls specified function with or without entering the debugger.
10425// This is used in unit tests to run code as if debugger is entered or simply
10426// to have a stack with C++ frame in the middle.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010427static MaybeObject* Runtime_ExecuteInDebugContext(Arguments args) {
ager@chromium.org357bf652010-04-12 11:30:10 +000010428 ASSERT(args.length() == 2);
10429 HandleScope scope;
10430 CONVERT_ARG_CHECKED(JSFunction, function, 0);
10431 CONVERT_BOOLEAN_CHECKED(without_debugger, args[1]);
10432
10433 Handle<Object> result;
10434 bool pending_exception;
10435 {
10436 if (without_debugger) {
10437 result = Execution::Call(function, Top::global(), 0, NULL,
10438 &pending_exception);
10439 } else {
10440 EnterDebugger enter_debugger;
10441 result = Execution::Call(function, Top::global(), 0, NULL,
10442 &pending_exception);
10443 }
10444 }
10445 if (!pending_exception) {
10446 return *result;
10447 } else {
10448 return Failure::Exception();
10449 }
10450}
10451
10452
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000010453// Sets a v8 flag.
10454static MaybeObject* Runtime_SetFlags(Arguments args) {
10455 CONVERT_CHECKED(String, arg, args[0]);
10456 SmartPointer<char> flags =
10457 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
10458 FlagList::SetFlagsFromString(*flags, StrLength(*flags));
10459 return Heap::undefined_value();
10460}
10461
10462
10463// Performs a GC.
10464// Presently, it only does a full GC.
10465static MaybeObject* Runtime_CollectGarbage(Arguments args) {
10466 Heap::CollectAllGarbage(true);
10467 return Heap::undefined_value();
10468}
10469
10470
10471// Gets the current heap usage.
10472static MaybeObject* Runtime_GetHeapUsage(Arguments args) {
10473 int usage = static_cast<int>(Heap::SizeOfObjects());
10474 if (!Smi::IsValid(usage)) {
10475 return *Factory::NewNumberFromInt(usage);
10476 }
10477 return Smi::FromInt(usage);
10478}
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010479#endif // ENABLE_DEBUGGER_SUPPORT
10480
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010481
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000010482#ifdef ENABLE_LOGGING_AND_PROFILING
lrn@chromium.org303ada72010-10-27 09:33:13 +000010483static MaybeObject* Runtime_ProfilerResume(Arguments args) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010484 NoHandleAllocation ha;
ager@chromium.org5c838252010-02-19 08:53:10 +000010485 ASSERT(args.length() == 2);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010486
10487 CONVERT_CHECKED(Smi, smi_modules, args[0]);
ager@chromium.org5c838252010-02-19 08:53:10 +000010488 CONVERT_CHECKED(Smi, smi_tag, args[1]);
10489 v8::V8::ResumeProfilerEx(smi_modules->value(), smi_tag->value());
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010490 return Heap::undefined_value();
10491}
10492
10493
lrn@chromium.org303ada72010-10-27 09:33:13 +000010494static MaybeObject* Runtime_ProfilerPause(Arguments args) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010495 NoHandleAllocation ha;
ager@chromium.org5c838252010-02-19 08:53:10 +000010496 ASSERT(args.length() == 2);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010497
10498 CONVERT_CHECKED(Smi, smi_modules, args[0]);
ager@chromium.org5c838252010-02-19 08:53:10 +000010499 CONVERT_CHECKED(Smi, smi_tag, args[1]);
10500 v8::V8::PauseProfilerEx(smi_modules->value(), smi_tag->value());
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010501 return Heap::undefined_value();
10502}
10503
10504#endif // ENABLE_LOGGING_AND_PROFILING
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010505
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010506// Finds the script object from the script data. NOTE: This operation uses
10507// heap traversal to find the function generated for the source position
10508// for the requested break point. For lazily compiled functions several heap
10509// traversals might be required rendering this operation as a rather slow
10510// operation. However for setting break points which is normally done through
10511// some kind of user interaction the performance is not crucial.
10512static Handle<Object> Runtime_GetScriptFromScriptName(
10513 Handle<String> script_name) {
10514 // Scan the heap for Script objects to find the script with the requested
10515 // script data.
10516 Handle<Script> script;
10517 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010518 HeapObject* obj = NULL;
10519 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010520 // If a script is found check if it has the script data requested.
10521 if (obj->IsScript()) {
10522 if (Script::cast(obj)->name()->IsString()) {
10523 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
10524 script = Handle<Script>(Script::cast(obj));
10525 }
10526 }
10527 }
10528 }
10529
10530 // If no script with the requested script data is found return undefined.
10531 if (script.is_null()) return Factory::undefined_value();
10532
10533 // Return the script found.
10534 return GetScriptWrapper(script);
10535}
10536
10537
10538// Get the script object from script data. NOTE: Regarding performance
10539// see the NOTE for GetScriptFromScriptData.
10540// args[0]: script data for the script to find the source for
lrn@chromium.org303ada72010-10-27 09:33:13 +000010541static MaybeObject* Runtime_GetScript(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010542 HandleScope scope;
10543
10544 ASSERT(args.length() == 1);
10545
10546 CONVERT_CHECKED(String, script_name, args[0]);
10547
10548 // Find the requested script.
10549 Handle<Object> result =
10550 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
10551 return *result;
10552}
10553
10554
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010555// Determines whether the given stack frame should be displayed in
10556// a stack trace. The caller is the error constructor that asked
10557// for the stack trace to be collected. The first time a construct
10558// call to this function is encountered it is skipped. The seen_caller
10559// in/out parameter is used to remember if the caller has been seen
10560// yet.
10561static bool ShowFrameInStackTrace(StackFrame* raw_frame, Object* caller,
10562 bool* seen_caller) {
10563 // Only display JS frames.
10564 if (!raw_frame->is_java_script())
10565 return false;
10566 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
10567 Object* raw_fun = frame->function();
10568 // Not sure when this can happen but skip it just in case.
10569 if (!raw_fun->IsJSFunction())
10570 return false;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010571 if ((raw_fun == caller) && !(*seen_caller)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010572 *seen_caller = true;
10573 return false;
10574 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010575 // Skip all frames until we've seen the caller. Also, skip the most
10576 // obvious builtin calls. Some builtin calls (such as Number.ADD
10577 // which is invoked using 'call') are very difficult to recognize
10578 // so we're leaving them in for now.
10579 return *seen_caller && !frame->receiver()->IsJSBuiltinsObject();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010580}
10581
10582
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010583// Collect the raw data for a stack trace. Returns an array of 4
10584// element segments each containing a receiver, function, code and
10585// native code offset.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010586static MaybeObject* Runtime_CollectStackTrace(Arguments args) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010587 ASSERT_EQ(args.length(), 2);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010588 Handle<Object> caller = args.at<Object>(0);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010589 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[1]);
10590
10591 HandleScope scope;
10592
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000010593 limit = Max(limit, 0); // Ensure that limit is not negative.
10594 int initial_size = Min(limit, 10);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010595 Handle<JSArray> result = Factory::NewJSArray(initial_size * 4);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010596
10597 StackFrameIterator iter;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010598 // If the caller parameter is a function we skip frames until we're
10599 // under it before starting to collect.
10600 bool seen_caller = !caller->IsJSFunction();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010601 int cursor = 0;
10602 int frames_seen = 0;
10603 while (!iter.done() && frames_seen < limit) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010604 StackFrame* raw_frame = iter.frame();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010605 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010606 frames_seen++;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010607 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010608 List<FrameSummary> frames(3); // Max 2 levels of inlining.
10609 frame->Summarize(&frames);
10610 for (int i = frames.length() - 1; i >= 0; i--) {
10611 Handle<Object> recv = frames[i].receiver();
10612 Handle<JSFunction> fun = frames[i].function();
10613 Handle<Code> code = frames[i].code();
10614 Handle<Smi> offset(Smi::FromInt(frames[i].offset()));
10615 FixedArray* elements = FixedArray::cast(result->elements());
10616 if (cursor + 3 < elements->length()) {
10617 elements->set(cursor++, *recv);
10618 elements->set(cursor++, *fun);
10619 elements->set(cursor++, *code);
10620 elements->set(cursor++, *offset);
10621 } else {
10622 SetElement(result, cursor++, recv);
10623 SetElement(result, cursor++, fun);
10624 SetElement(result, cursor++, code);
10625 SetElement(result, cursor++, offset);
10626 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010627 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010628 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010629 iter.Advance();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010630 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010631
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010632 result->set_length(Smi::FromInt(cursor));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010633 return *result;
10634}
10635
10636
ager@chromium.org3811b432009-10-28 14:53:37 +000010637// Returns V8 version as a string.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010638static MaybeObject* Runtime_GetV8Version(Arguments args) {
ager@chromium.org3811b432009-10-28 14:53:37 +000010639 ASSERT_EQ(args.length(), 0);
10640
10641 NoHandleAllocation ha;
10642
10643 const char* version_string = v8::V8::GetVersion();
10644
10645 return Heap::AllocateStringFromAscii(CStrVector(version_string), NOT_TENURED);
10646}
10647
10648
lrn@chromium.org303ada72010-10-27 09:33:13 +000010649static MaybeObject* Runtime_Abort(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010650 ASSERT(args.length() == 2);
10651 OS::PrintError("abort: %s\n", reinterpret_cast<char*>(args[0]) +
10652 Smi::cast(args[1])->value());
10653 Top::PrintStack();
10654 OS::Abort();
10655 UNREACHABLE();
10656 return NULL;
10657}
10658
10659
lrn@chromium.org303ada72010-10-27 09:33:13 +000010660static MaybeObject* Runtime_GetFromCache(Arguments args) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010661 // This is only called from codegen, so checks might be more lax.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000010662 CONVERT_CHECKED(JSFunctionResultCache, cache, args[0]);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010663 Object* key = args[1];
10664
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000010665 int finger_index = cache->finger_index();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010666 Object* o = cache->get(finger_index);
10667 if (o == key) {
10668 // The fastest case: hit the same place again.
10669 return cache->get(finger_index + 1);
10670 }
10671
10672 for (int i = finger_index - 2;
10673 i >= JSFunctionResultCache::kEntriesIndex;
10674 i -= 2) {
10675 o = cache->get(i);
10676 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000010677 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010678 return cache->get(i + 1);
10679 }
10680 }
10681
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000010682 int size = cache->size();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010683 ASSERT(size <= cache->length());
10684
10685 for (int i = size - 2; i > finger_index; i -= 2) {
10686 o = cache->get(i);
10687 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000010688 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010689 return cache->get(i + 1);
10690 }
10691 }
10692
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000010693 // There is no value in the cache. Invoke the function and cache result.
10694 HandleScope scope;
10695
10696 Handle<JSFunctionResultCache> cache_handle(cache);
10697 Handle<Object> key_handle(key);
10698 Handle<Object> value;
10699 {
10700 Handle<JSFunction> factory(JSFunction::cast(
10701 cache_handle->get(JSFunctionResultCache::kFactoryIndex)));
10702 // TODO(antonm): consider passing a receiver when constructing a cache.
10703 Handle<Object> receiver(Top::global_context()->global());
10704 // This handle is nor shared, nor used later, so it's safe.
10705 Object** argv[] = { key_handle.location() };
10706 bool pending_exception = false;
10707 value = Execution::Call(factory,
10708 receiver,
10709 1,
10710 argv,
10711 &pending_exception);
10712 if (pending_exception) return Failure::Exception();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010713 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000010714
10715#ifdef DEBUG
10716 cache_handle->JSFunctionResultCacheVerify();
10717#endif
10718
10719 // Function invocation may have cleared the cache. Reread all the data.
10720 finger_index = cache_handle->finger_index();
10721 size = cache_handle->size();
10722
10723 // If we have spare room, put new data into it, otherwise evict post finger
10724 // entry which is likely to be the least recently used.
10725 int index = -1;
10726 if (size < cache_handle->length()) {
10727 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize);
10728 index = size;
10729 } else {
10730 index = finger_index + JSFunctionResultCache::kEntrySize;
10731 if (index == cache_handle->length()) {
10732 index = JSFunctionResultCache::kEntriesIndex;
10733 }
10734 }
10735
10736 ASSERT(index % 2 == 0);
10737 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
10738 ASSERT(index < cache_handle->length());
10739
10740 cache_handle->set(index, *key_handle);
10741 cache_handle->set(index + 1, *value);
10742 cache_handle->set_finger_index(index);
10743
10744#ifdef DEBUG
10745 cache_handle->JSFunctionResultCacheVerify();
10746#endif
10747
10748 return *value;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010749}
10750
kasper.lund44510672008-07-25 07:37:58 +000010751#ifdef DEBUG
10752// ListNatives is ONLY used by the fuzz-natives.js in debug mode
10753// Exclude the code in release mode.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010754static MaybeObject* Runtime_ListNatives(Arguments args) {
mads.s.ager31e71382008-08-13 09:32:07 +000010755 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010756 HandleScope scope;
10757 Handle<JSArray> result = Factory::NewJSArray(0);
10758 int index = 0;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000010759 bool inline_runtime_functions = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +000010760#define ADD_ENTRY(Name, argc, ressize) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010761 { \
10762 HandleScope inner; \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000010763 Handle<String> name; \
10764 /* Inline runtime functions have an underscore in front of the name. */ \
10765 if (inline_runtime_functions) { \
10766 name = Factory::NewStringFromAscii( \
10767 Vector<const char>("_" #Name, StrLength("_" #Name))); \
10768 } else { \
10769 name = Factory::NewStringFromAscii( \
10770 Vector<const char>(#Name, StrLength(#Name))); \
10771 } \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010772 Handle<JSArray> pair = Factory::NewJSArray(0); \
10773 SetElement(pair, 0, name); \
10774 SetElement(pair, 1, Handle<Smi>(Smi::FromInt(argc))); \
10775 SetElement(result, index++, pair); \
10776 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000010777 inline_runtime_functions = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010778 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000010779 inline_runtime_functions = true;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010780 INLINE_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000010781 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010782#undef ADD_ENTRY
10783 return *result;
10784}
kasper.lund44510672008-07-25 07:37:58 +000010785#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010786
10787
lrn@chromium.org303ada72010-10-27 09:33:13 +000010788static MaybeObject* Runtime_Log(Arguments args) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000010789 ASSERT(args.length() == 2);
ager@chromium.org381abbb2009-02-25 13:23:22 +000010790 CONVERT_CHECKED(String, format, args[0]);
10791 CONVERT_CHECKED(JSArray, elms, args[1]);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000010792 Vector<const char> chars = format->ToAsciiVector();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000010793 Logger::LogRuntime(chars, elms);
10794 return Heap::undefined_value();
10795}
10796
10797
lrn@chromium.org303ada72010-10-27 09:33:13 +000010798static MaybeObject* Runtime_IS_VAR(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010799 UNREACHABLE(); // implemented as macro in the parser
10800 return NULL;
10801}
10802
10803
10804// ----------------------------------------------------------------------------
10805// Implementation of Runtime
10806
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010807#define F(name, number_of_args, result_size) \
10808 { Runtime::k##name, Runtime::RUNTIME, #name, \
10809 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010810
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010811
10812#define I(name, number_of_args, result_size) \
10813 { Runtime::kInline##name, Runtime::INLINE, \
10814 "_" #name, NULL, number_of_args, result_size },
10815
10816Runtime::Function kIntrinsicFunctions[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010817 RUNTIME_FUNCTION_LIST(F)
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010818 INLINE_FUNCTION_LIST(I)
10819 INLINE_RUNTIME_FUNCTION_LIST(I)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010820};
10821
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010822
lrn@chromium.org303ada72010-10-27 09:33:13 +000010823MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Object* dictionary) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010824 ASSERT(dictionary != NULL);
10825 ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
10826 for (int i = 0; i < kNumFunctions; ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000010827 Object* name_symbol;
10828 { MaybeObject* maybe_name_symbol =
10829 Heap::LookupAsciiSymbol(kIntrinsicFunctions[i].name);
10830 if (!maybe_name_symbol->ToObject(&name_symbol)) return maybe_name_symbol;
10831 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010832 StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010833 { MaybeObject* maybe_dictionary = string_dictionary->Add(
10834 String::cast(name_symbol),
10835 Smi::FromInt(i),
10836 PropertyDetails(NONE, NORMAL));
10837 if (!maybe_dictionary->ToObject(&dictionary)) {
10838 // Non-recoverable failure. Calling code must restart heap
10839 // initialization.
10840 return maybe_dictionary;
10841 }
10842 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010843 }
10844 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010845}
10846
10847
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010848Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
10849 int entry = Heap::intrinsic_function_names()->FindEntry(*name);
10850 if (entry != kNotFound) {
10851 Object* smi_index = Heap::intrinsic_function_names()->ValueAt(entry);
10852 int function_index = Smi::cast(smi_index)->value();
10853 return &(kIntrinsicFunctions[function_index]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010854 }
10855 return NULL;
10856}
10857
10858
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010859Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
10860 return &(kIntrinsicFunctions[static_cast<int>(id)]);
10861}
10862
10863
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010864void Runtime::PerformGC(Object* result) {
10865 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010866 if (failure->IsRetryAfterGC()) {
10867 // Try to do a garbage collection; ignore it if it fails. The C
10868 // entry stub will throw an out-of-memory exception in that case.
whesse@chromium.org4a5224e2010-10-20 12:37:07 +000010869 Heap::CollectGarbage(failure->allocation_space());
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010870 } else {
10871 // Handle last resort GC and make sure to allow future allocations
10872 // to grow the heap without causing GCs (if possible).
10873 Counters::gc_last_resort_from_js.Increment();
ager@chromium.orgab99eea2009-08-25 07:05:41 +000010874 Heap::CollectAllGarbage(false);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010875 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010876}
10877
10878
10879} } // namespace v8::internal