blob: 2f1f54c6965cab37030644e5d29e3794a7c9c0cd [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 if (result.type() == CALLBACKS) {
749 Object* structure = result.GetCallbackObject();
ager@chromium.org5c838252010-02-19 08:53:10 +0000750 if (structure->IsProxy() || structure->IsAccessorInfo()) {
751 // Property that is internally implemented as a callback or
752 // an API defined callback.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000753 Object* value;
754 { MaybeObject* maybe_value = obj->GetPropertyWithCallback(
755 *obj, structure, *name, result.holder());
756 if (!maybe_value->ToObject(&value)) return maybe_value;
757 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000758 elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
759 elms->set(VALUE_INDEX, value);
760 elms->set(WRITABLE_INDEX, Heap::ToBoolean(!result.IsReadOnly()));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000761 } else if (structure->IsFixedArray()) {
762 // __defineGetter__/__defineSetter__ callback.
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000763 elms->set(IS_ACCESSOR_INDEX, Heap::true_value());
764 elms->set(GETTER_INDEX, FixedArray::cast(structure)->get(0));
765 elms->set(SETTER_INDEX, FixedArray::cast(structure)->get(1));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000766 } else {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000767 return Heap::undefined_value();
768 }
769 } else {
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000770 elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
771 elms->set(VALUE_INDEX, result.GetLazyValue());
772 elms->set(WRITABLE_INDEX, Heap::ToBoolean(!result.IsReadOnly()));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000773 }
774
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000775 elms->set(ENUMERABLE_INDEX, Heap::ToBoolean(!result.IsDontEnum()));
776 elms->set(CONFIGURABLE_INDEX, Heap::ToBoolean(!result.IsDontDelete()));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000777 return *desc;
778}
779
780
lrn@chromium.org303ada72010-10-27 09:33:13 +0000781static MaybeObject* Runtime_PreventExtensions(Arguments args) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000782 ASSERT(args.length() == 1);
783 CONVERT_CHECKED(JSObject, obj, args[0]);
784 return obj->PreventExtensions();
785}
786
lrn@chromium.org303ada72010-10-27 09:33:13 +0000787static MaybeObject* Runtime_IsExtensible(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000788 ASSERT(args.length() == 1);
789 CONVERT_CHECKED(JSObject, obj, args[0]);
790 return obj->map()->is_extensible() ? Heap::true_value()
791 : Heap::false_value();
792}
793
794
lrn@chromium.org303ada72010-10-27 09:33:13 +0000795static MaybeObject* Runtime_RegExpCompile(Arguments args) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000796 HandleScope scope;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000797 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000798 CONVERT_ARG_CHECKED(JSRegExp, re, 0);
799 CONVERT_ARG_CHECKED(String, pattern, 1);
800 CONVERT_ARG_CHECKED(String, flags, 2);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000801 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags);
802 if (result.is_null()) return Failure::Exception();
803 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000804}
805
806
lrn@chromium.org303ada72010-10-27 09:33:13 +0000807static MaybeObject* Runtime_CreateApiFunction(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000808 HandleScope scope;
809 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000810 CONVERT_ARG_CHECKED(FunctionTemplateInfo, data, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000811 return *Factory::CreateApiFunction(data);
812}
813
814
lrn@chromium.org303ada72010-10-27 09:33:13 +0000815static MaybeObject* Runtime_IsTemplate(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000816 ASSERT(args.length() == 1);
817 Object* arg = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000818 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000819 return Heap::ToBoolean(result);
820}
821
822
lrn@chromium.org303ada72010-10-27 09:33:13 +0000823static MaybeObject* Runtime_GetTemplateField(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000824 ASSERT(args.length() == 2);
825 CONVERT_CHECKED(HeapObject, templ, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000826 CONVERT_CHECKED(Smi, field, args[1]);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000827 int index = field->value();
828 int offset = index * kPointerSize + HeapObject::kHeaderSize;
829 InstanceType type = templ->map()->instance_type();
830 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
831 type == OBJECT_TEMPLATE_INFO_TYPE);
832 RUNTIME_ASSERT(offset > 0);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000833 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000834 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
835 } else {
836 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
837 }
838 return *HeapObject::RawField(templ, offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000839}
840
841
lrn@chromium.org303ada72010-10-27 09:33:13 +0000842static MaybeObject* Runtime_DisableAccessChecks(Arguments args) {
ager@chromium.org870a0b62008-11-04 11:43:05 +0000843 ASSERT(args.length() == 1);
844 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +0000845 Map* old_map = object->map();
846 bool needs_access_checks = old_map->is_access_check_needed();
847 if (needs_access_checks) {
848 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000849 Object* new_map;
850 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
851 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
852 }
ager@chromium.org32912102009-01-16 10:38:43 +0000853
854 Map::cast(new_map)->set_is_access_check_needed(false);
855 object->set_map(Map::cast(new_map));
856 }
ager@chromium.org870a0b62008-11-04 11:43:05 +0000857 return needs_access_checks ? Heap::true_value() : Heap::false_value();
858}
859
860
lrn@chromium.org303ada72010-10-27 09:33:13 +0000861static MaybeObject* Runtime_EnableAccessChecks(Arguments args) {
ager@chromium.org870a0b62008-11-04 11:43:05 +0000862 ASSERT(args.length() == 1);
863 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +0000864 Map* old_map = object->map();
865 if (!old_map->is_access_check_needed()) {
866 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000867 Object* new_map;
868 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
869 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
870 }
ager@chromium.org32912102009-01-16 10:38:43 +0000871
872 Map::cast(new_map)->set_is_access_check_needed(true);
873 object->set_map(Map::cast(new_map));
874 }
ager@chromium.org870a0b62008-11-04 11:43:05 +0000875 return Heap::undefined_value();
876}
877
878
lrn@chromium.org303ada72010-10-27 09:33:13 +0000879static Failure* ThrowRedeclarationError(const char* type, Handle<String> name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000880 HandleScope scope;
881 Handle<Object> type_handle = Factory::NewStringFromAscii(CStrVector(type));
882 Handle<Object> args[2] = { type_handle, name };
883 Handle<Object> error =
884 Factory::NewTypeError("redeclaration", HandleVector(args, 2));
885 return Top::Throw(*error);
886}
887
888
lrn@chromium.org303ada72010-10-27 09:33:13 +0000889static MaybeObject* Runtime_DeclareGlobals(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000890 HandleScope scope;
891 Handle<GlobalObject> global = Handle<GlobalObject>(Top::context()->global());
892
ager@chromium.org3811b432009-10-28 14:53:37 +0000893 Handle<Context> context = args.at<Context>(0);
894 CONVERT_ARG_CHECKED(FixedArray, pairs, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000895 bool is_eval = Smi::cast(args[2])->value() == 1;
896
897 // Compute the property attributes. According to ECMA-262, section
898 // 13, page 71, the property must be read-only and
899 // non-deletable. However, neither SpiderMonkey nor KJS creates the
900 // property as read-only, so we don't either.
901 PropertyAttributes base = is_eval ? NONE : DONT_DELETE;
902
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000903 // Traverse the name/value pairs and set the properties.
904 int length = pairs->length();
905 for (int i = 0; i < length; i += 2) {
906 HandleScope scope;
907 Handle<String> name(String::cast(pairs->get(i)));
908 Handle<Object> value(pairs->get(i + 1));
909
910 // We have to declare a global const property. To capture we only
911 // assign to it when evaluating the assignment for "const x =
912 // <expr>" the initial value is the hole.
913 bool is_const_property = value->IsTheHole();
914
915 if (value->IsUndefined() || is_const_property) {
916 // Lookup the property in the global object, and don't set the
917 // value of the variable if the property is already there.
918 LookupResult lookup;
919 global->Lookup(*name, &lookup);
920 if (lookup.IsProperty()) {
921 // Determine if the property is local by comparing the holder
922 // against the global object. The information will be used to
923 // avoid throwing re-declaration errors when declaring
924 // variables or constants that exist in the prototype chain.
925 bool is_local = (*global == lookup.holder());
926 // Get the property attributes and determine if the property is
927 // read-only.
928 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
929 bool is_read_only = (attributes & READ_ONLY) != 0;
930 if (lookup.type() == INTERCEPTOR) {
931 // If the interceptor says the property is there, we
932 // just return undefined without overwriting the property.
933 // Otherwise, we continue to setting the property.
934 if (attributes != ABSENT) {
935 // Check if the existing property conflicts with regards to const.
936 if (is_local && (is_read_only || is_const_property)) {
937 const char* type = (is_read_only) ? "const" : "var";
938 return ThrowRedeclarationError(type, name);
939 };
940 // The property already exists without conflicting: Go to
941 // the next declaration.
942 continue;
943 }
944 // Fall-through and introduce the absent property by using
945 // SetProperty.
946 } else {
947 if (is_local && (is_read_only || is_const_property)) {
948 const char* type = (is_read_only) ? "const" : "var";
949 return ThrowRedeclarationError(type, name);
950 }
951 // The property already exists without conflicting: Go to
952 // the next declaration.
953 continue;
954 }
955 }
956 } else {
957 // Copy the function and update its context. Use it as value.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000958 Handle<SharedFunctionInfo> shared =
959 Handle<SharedFunctionInfo>::cast(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000960 Handle<JSFunction> function =
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000961 Factory::NewFunctionFromSharedFunctionInfo(shared, context, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000962 value = function;
963 }
964
965 LookupResult lookup;
966 global->LocalLookup(*name, &lookup);
967
968 PropertyAttributes attributes = is_const_property
969 ? static_cast<PropertyAttributes>(base | READ_ONLY)
970 : base;
971
972 if (lookup.IsProperty()) {
973 // There's a local property that we need to overwrite because
974 // we're either declaring a function or there's an interceptor
975 // that claims the property is absent.
976
977 // Check for conflicting re-declarations. We cannot have
978 // conflicting types in case of intercepted properties because
979 // they are absent.
980 if (lookup.type() != INTERCEPTOR &&
981 (lookup.IsReadOnly() || is_const_property)) {
982 const char* type = (lookup.IsReadOnly()) ? "const" : "var";
983 return ThrowRedeclarationError(type, name);
984 }
985 SetProperty(global, name, value, attributes);
986 } else {
987 // If a property with this name does not already exist on the
988 // global object add the property locally. We take special
989 // precautions to always add it as a local property even in case
990 // of callbacks in the prototype chain (this rules out using
991 // SetProperty). Also, we must use the handle-based version to
992 // avoid GC issues.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000993 SetLocalPropertyIgnoreAttributes(global, name, value, attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000994 }
995 }
ager@chromium.org7c537e22008-10-16 08:43:32 +0000996
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000997 return Heap::undefined_value();
998}
999
1000
lrn@chromium.org303ada72010-10-27 09:33:13 +00001001static MaybeObject* Runtime_DeclareContextSlot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001002 HandleScope scope;
ager@chromium.org7c537e22008-10-16 08:43:32 +00001003 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001004
ager@chromium.org7c537e22008-10-16 08:43:32 +00001005 CONVERT_ARG_CHECKED(Context, context, 0);
1006 Handle<String> name(String::cast(args[1]));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001007 PropertyAttributes mode =
ager@chromium.org7c537e22008-10-16 08:43:32 +00001008 static_cast<PropertyAttributes>(Smi::cast(args[2])->value());
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001009 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001010 Handle<Object> initial_value(args[3]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001011
1012 // Declarations are always done in the function context.
1013 context = Handle<Context>(context->fcontext());
1014
1015 int index;
1016 PropertyAttributes attributes;
1017 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001018 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001019 context->Lookup(name, flags, &index, &attributes);
1020
1021 if (attributes != ABSENT) {
1022 // The name was declared before; check for conflicting
1023 // re-declarations: This is similar to the code in parser.cc in
1024 // the AstBuildingParser::Declare function.
1025 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
1026 // Functions are not read-only.
1027 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
1028 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
1029 return ThrowRedeclarationError(type, name);
1030 }
1031
1032 // Initialize it if necessary.
1033 if (*initial_value != NULL) {
1034 if (index >= 0) {
1035 // The variable or constant context slot should always be in
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001036 // the function context or the arguments object.
1037 if (holder->IsContext()) {
1038 ASSERT(holder.is_identical_to(context));
1039 if (((attributes & READ_ONLY) == 0) ||
1040 context->get(index)->IsTheHole()) {
1041 context->set(index, *initial_value);
1042 }
1043 } else {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001044 // The holder is an arguments object.
1045 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
1046 SetElement(arguments, index, initial_value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001047 }
1048 } else {
1049 // Slow case: The property is not in the FixedArray part of the context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001050 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001051 SetProperty(context_ext, name, initial_value, mode);
1052 }
1053 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001054
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001055 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001056 // The property is not in the function context. It needs to be
1057 // "declared" in the function context's extension context, or in the
1058 // global context.
1059 Handle<JSObject> context_ext;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001060 if (context->has_extension()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001061 // The function context's extension context exists - use it.
1062 context_ext = Handle<JSObject>(context->extension());
1063 } else {
1064 // The function context's extension context does not exists - allocate
1065 // it.
1066 context_ext = Factory::NewJSObject(Top::context_extension_function());
1067 // And store it in the extension slot.
1068 context->set_extension(*context_ext);
1069 }
1070 ASSERT(*context_ext != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001071
ager@chromium.org7c537e22008-10-16 08:43:32 +00001072 // Declare the property by setting it to the initial value if provided,
1073 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
1074 // constant declarations).
1075 ASSERT(!context_ext->HasLocalProperty(*name));
1076 Handle<Object> value(Heap::undefined_value());
1077 if (*initial_value != NULL) value = initial_value;
1078 SetProperty(context_ext, name, value, mode);
1079 ASSERT(context_ext->GetLocalPropertyAttribute(*name) == mode);
1080 }
1081
1082 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001083}
1084
1085
lrn@chromium.org303ada72010-10-27 09:33:13 +00001086static MaybeObject* Runtime_InitializeVarGlobal(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001087 NoHandleAllocation nha;
1088
1089 // Determine if we need to assign to the variable if it already
1090 // exists (based on the number of arguments).
1091 RUNTIME_ASSERT(args.length() == 1 || args.length() == 2);
1092 bool assign = args.length() == 2;
1093
1094 CONVERT_ARG_CHECKED(String, name, 0);
1095 GlobalObject* global = Top::context()->global();
1096
1097 // According to ECMA-262, section 12.2, page 62, the property must
1098 // not be deletable.
1099 PropertyAttributes attributes = DONT_DELETE;
1100
1101 // Lookup the property locally in the global object. If it isn't
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001102 // there, there is a property with this name in the prototype chain.
1103 // We follow Safari and Firefox behavior and only set the property
1104 // locally if there is an explicit initialization value that we have
1105 // to assign to the property. When adding the property we take
1106 // special precautions to always add it as a local property even in
1107 // case of callbacks in the prototype chain (this rules out using
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001108 // SetProperty). We have SetLocalPropertyIgnoreAttributes for
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001109 // this.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001110 // Note that objects can have hidden prototypes, so we need to traverse
1111 // the whole chain of hidden prototypes to do a 'local' lookup.
1112 JSObject* real_holder = global;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001113 LookupResult lookup;
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001114 while (true) {
1115 real_holder->LocalLookup(*name, &lookup);
1116 if (lookup.IsProperty()) {
1117 // Determine if this is a redeclaration of something read-only.
1118 if (lookup.IsReadOnly()) {
1119 // If we found readonly property on one of hidden prototypes,
1120 // just shadow it.
1121 if (real_holder != Top::context()->global()) break;
1122 return ThrowRedeclarationError("const", name);
1123 }
1124
1125 // Determine if this is a redeclaration of an intercepted read-only
1126 // property and figure out if the property exists at all.
1127 bool found = true;
1128 PropertyType type = lookup.type();
1129 if (type == INTERCEPTOR) {
1130 HandleScope handle_scope;
1131 Handle<JSObject> holder(real_holder);
1132 PropertyAttributes intercepted = holder->GetPropertyAttribute(*name);
1133 real_holder = *holder;
1134 if (intercepted == ABSENT) {
1135 // The interceptor claims the property isn't there. We need to
1136 // make sure to introduce it.
1137 found = false;
1138 } else if ((intercepted & READ_ONLY) != 0) {
1139 // The property is present, but read-only. Since we're trying to
1140 // overwrite it with a variable declaration we must throw a
1141 // re-declaration error. However if we found readonly property
1142 // on one of hidden prototypes, just shadow it.
1143 if (real_holder != Top::context()->global()) break;
1144 return ThrowRedeclarationError("const", name);
1145 }
1146 }
1147
1148 if (found && !assign) {
1149 // The global property is there and we're not assigning any value
1150 // to it. Just return.
1151 return Heap::undefined_value();
1152 }
1153
1154 // Assign the value (or undefined) to the property.
1155 Object* value = (assign) ? args[1] : Heap::undefined_value();
1156 return real_holder->SetProperty(&lookup, *name, value, attributes);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001157 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001158
1159 Object* proto = real_holder->GetPrototype();
1160 if (!proto->IsJSObject())
1161 break;
1162
1163 if (!JSObject::cast(proto)->map()->is_hidden_prototype())
1164 break;
1165
1166 real_holder = JSObject::cast(proto);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001167 }
1168
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001169 global = Top::context()->global();
1170 if (assign) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001171 return global->SetLocalPropertyIgnoreAttributes(*name,
1172 args[1],
1173 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001174 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001175 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001176}
1177
1178
lrn@chromium.org303ada72010-10-27 09:33:13 +00001179static MaybeObject* Runtime_InitializeConstGlobal(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001180 // All constants are declared with an initial value. The name
1181 // of the constant is the first argument and the initial value
1182 // is the second.
1183 RUNTIME_ASSERT(args.length() == 2);
1184 CONVERT_ARG_CHECKED(String, name, 0);
1185 Handle<Object> value = args.at<Object>(1);
1186
1187 // Get the current global object from top.
1188 GlobalObject* global = Top::context()->global();
1189
1190 // According to ECMA-262, section 12.2, page 62, the property must
1191 // not be deletable. Since it's a const, it must be READ_ONLY too.
1192 PropertyAttributes attributes =
1193 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
1194
1195 // Lookup the property locally in the global object. If it isn't
1196 // there, we add the property and take special precautions to always
1197 // add it as a local property even in case of callbacks in the
1198 // prototype chain (this rules out using SetProperty).
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001199 // We use SetLocalPropertyIgnoreAttributes instead
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001200 LookupResult lookup;
1201 global->LocalLookup(*name, &lookup);
1202 if (!lookup.IsProperty()) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001203 return global->SetLocalPropertyIgnoreAttributes(*name,
1204 *value,
1205 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001206 }
1207
1208 // Determine if this is a redeclaration of something not
1209 // read-only. In case the result is hidden behind an interceptor we
1210 // need to ask it for the property attributes.
1211 if (!lookup.IsReadOnly()) {
1212 if (lookup.type() != INTERCEPTOR) {
1213 return ThrowRedeclarationError("var", name);
1214 }
1215
1216 PropertyAttributes intercepted = global->GetPropertyAttribute(*name);
1217
1218 // Throw re-declaration error if the intercepted property is present
1219 // but not read-only.
1220 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
1221 return ThrowRedeclarationError("var", name);
1222 }
1223
1224 // Restore global object from context (in case of GC) and continue
1225 // with setting the value because the property is either absent or
1226 // read-only. We also have to do redo the lookup.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001227 HandleScope handle_scope;
1228 Handle<GlobalObject>global(Top::context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001229
1230 // BUG 1213579: Handle the case where we have to set a read-only
1231 // property through an interceptor and only do it if it's
1232 // uninitialized, e.g. the hole. Nirk...
lrn@chromium.org303ada72010-10-27 09:33:13 +00001233 SetProperty(global, name, value, attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001234 return *value;
1235 }
1236
1237 // Set the value, but only we're assigning the initial value to a
1238 // constant. For now, we determine this by checking if the
1239 // current value is the hole.
1240 PropertyType type = lookup.type();
1241 if (type == FIELD) {
1242 FixedArray* properties = global->properties();
1243 int index = lookup.GetFieldIndex();
1244 if (properties->get(index)->IsTheHole()) {
1245 properties->set(index, *value);
1246 }
1247 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001248 if (global->GetNormalizedProperty(&lookup)->IsTheHole()) {
1249 global->SetNormalizedProperty(&lookup, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001250 }
1251 } else {
1252 // Ignore re-initialization of constants that have already been
1253 // assigned a function value.
1254 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
1255 }
1256
1257 // Use the set value as the result of the operation.
1258 return *value;
1259}
1260
1261
lrn@chromium.org303ada72010-10-27 09:33:13 +00001262static MaybeObject* Runtime_InitializeConstContextSlot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001263 HandleScope scope;
1264 ASSERT(args.length() == 3);
1265
1266 Handle<Object> value(args[0]);
1267 ASSERT(!value->IsTheHole());
1268 CONVERT_ARG_CHECKED(Context, context, 1);
1269 Handle<String> name(String::cast(args[2]));
1270
1271 // Initializations are always done in the function context.
1272 context = Handle<Context>(context->fcontext());
1273
1274 int index;
1275 PropertyAttributes attributes;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001276 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001277 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001278 context->Lookup(name, flags, &index, &attributes);
1279
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001280 // In most situations, the property introduced by the const
1281 // declaration should be present in the context extension object.
1282 // However, because declaration and initialization are separate, the
1283 // property might have been deleted (if it was introduced by eval)
1284 // before we reach the initialization point.
1285 //
1286 // Example:
1287 //
1288 // function f() { eval("delete x; const x;"); }
1289 //
1290 // In that case, the initialization behaves like a normal assignment
1291 // to property 'x'.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001292 if (index >= 0) {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001293 // Property was found in a context.
1294 if (holder->IsContext()) {
1295 // The holder cannot be the function context. If it is, there
1296 // should have been a const redeclaration error when declaring
1297 // the const property.
1298 ASSERT(!holder.is_identical_to(context));
1299 if ((attributes & READ_ONLY) == 0) {
1300 Handle<Context>::cast(holder)->set(index, *value);
1301 }
1302 } else {
1303 // The holder is an arguments object.
1304 ASSERT((attributes & READ_ONLY) == 0);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001305 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
1306 SetElement(arguments, index, value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001307 }
1308 return *value;
1309 }
1310
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001311 // The property could not be found, we introduce it in the global
1312 // context.
1313 if (attributes == ABSENT) {
1314 Handle<JSObject> global = Handle<JSObject>(Top::context()->global());
1315 SetProperty(global, name, value, NONE);
1316 return *value;
1317 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001318
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001319 // The property was present in a context extension object.
1320 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001321
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001322 if (*context_ext == context->extension()) {
1323 // This is the property that was introduced by the const
1324 // declaration. Set it if it hasn't been set before. NOTE: We
1325 // cannot use GetProperty() to get the current value as it
1326 // 'unholes' the value.
1327 LookupResult lookup;
1328 context_ext->LocalLookupRealNamedProperty(*name, &lookup);
1329 ASSERT(lookup.IsProperty()); // the property was declared
1330 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
1331
1332 PropertyType type = lookup.type();
1333 if (type == FIELD) {
1334 FixedArray* properties = context_ext->properties();
1335 int index = lookup.GetFieldIndex();
1336 if (properties->get(index)->IsTheHole()) {
1337 properties->set(index, *value);
1338 }
1339 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001340 if (context_ext->GetNormalizedProperty(&lookup)->IsTheHole()) {
1341 context_ext->SetNormalizedProperty(&lookup, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001342 }
1343 } else {
1344 // We should not reach here. Any real, named property should be
1345 // either a field or a dictionary slot.
1346 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001347 }
1348 } else {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001349 // The property was found in a different context extension object.
1350 // Set it if it is not a read-only property.
1351 if ((attributes & READ_ONLY) == 0) {
1352 Handle<Object> set = SetProperty(context_ext, name, value, attributes);
1353 // Setting a property might throw an exception. Exceptions
1354 // are converted to empty handles in handle operations. We
1355 // need to convert back to exceptions here.
1356 if (set.is_null()) {
1357 ASSERT(Top::has_pending_exception());
1358 return Failure::Exception();
1359 }
1360 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001361 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001362
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001363 return *value;
1364}
1365
1366
lrn@chromium.org303ada72010-10-27 09:33:13 +00001367static MaybeObject* Runtime_OptimizeObjectForAddingMultipleProperties(
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001368 Arguments args) {
1369 HandleScope scope;
1370 ASSERT(args.length() == 2);
1371 CONVERT_ARG_CHECKED(JSObject, object, 0);
1372 CONVERT_SMI_CHECKED(properties, args[1]);
1373 if (object->HasFastProperties()) {
1374 NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
1375 }
1376 return *object;
1377}
1378
1379
lrn@chromium.org303ada72010-10-27 09:33:13 +00001380static MaybeObject* Runtime_RegExpExec(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001381 HandleScope scope;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001382 ASSERT(args.length() == 4);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001383 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
1384 CONVERT_ARG_CHECKED(String, subject, 1);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001385 // Due to the way the JS calls are constructed this must be less than the
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001386 // length of a string, i.e. it is always a Smi. We check anyway for security.
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001387 CONVERT_SMI_CHECKED(index, args[2]);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001388 CONVERT_ARG_CHECKED(JSArray, last_match_info, 3);
ager@chromium.org41826e72009-03-30 13:30:57 +00001389 RUNTIME_ASSERT(last_match_info->HasFastElements());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001390 RUNTIME_ASSERT(index >= 0);
1391 RUNTIME_ASSERT(index <= subject->length());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001392 Counters::regexp_entry_runtime.Increment();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001393 Handle<Object> result = RegExpImpl::Exec(regexp,
1394 subject,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001395 index,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001396 last_match_info);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001397 if (result.is_null()) return Failure::Exception();
1398 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001399}
1400
1401
lrn@chromium.org303ada72010-10-27 09:33:13 +00001402static MaybeObject* Runtime_RegExpConstructResult(Arguments args) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001403 ASSERT(args.length() == 3);
1404 CONVERT_SMI_CHECKED(elements_count, args[0]);
1405 if (elements_count > JSArray::kMaxFastElementsLength) {
1406 return Top::ThrowIllegalOperation();
1407 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00001408 Object* new_object;
1409 { MaybeObject* maybe_new_object =
1410 Heap::AllocateFixedArrayWithHoles(elements_count);
1411 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1412 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001413 FixedArray* elements = FixedArray::cast(new_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001414 { MaybeObject* maybe_new_object = Heap::AllocateRaw(JSRegExpResult::kSize,
1415 NEW_SPACE,
1416 OLD_POINTER_SPACE);
1417 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1418 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001419 {
1420 AssertNoAllocation no_gc;
1421 HandleScope scope;
1422 reinterpret_cast<HeapObject*>(new_object)->
1423 set_map(Top::global_context()->regexp_result_map());
1424 }
1425 JSArray* array = JSArray::cast(new_object);
1426 array->set_properties(Heap::empty_fixed_array());
1427 array->set_elements(elements);
1428 array->set_length(Smi::FromInt(elements_count));
1429 // Write in-object properties after the length of the array.
1430 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]);
1431 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]);
1432 return array;
1433}
1434
1435
lrn@chromium.org303ada72010-10-27 09:33:13 +00001436static MaybeObject* Runtime_RegExpInitializeObject(Arguments args) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00001437 AssertNoAllocation no_alloc;
1438 ASSERT(args.length() == 5);
1439 CONVERT_CHECKED(JSRegExp, regexp, args[0]);
1440 CONVERT_CHECKED(String, source, args[1]);
1441
1442 Object* global = args[2];
1443 if (!global->IsTrue()) global = Heap::false_value();
1444
1445 Object* ignoreCase = args[3];
1446 if (!ignoreCase->IsTrue()) ignoreCase = Heap::false_value();
1447
1448 Object* multiline = args[4];
1449 if (!multiline->IsTrue()) multiline = Heap::false_value();
1450
1451 Map* map = regexp->map();
1452 Object* constructor = map->constructor();
1453 if (constructor->IsJSFunction() &&
1454 JSFunction::cast(constructor)->initial_map() == map) {
1455 // If we still have the original map, set in-object properties directly.
1456 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source);
1457 // TODO(lrn): Consider skipping write barrier on booleans as well.
1458 // Both true and false should be in oldspace at all times.
1459 regexp->InObjectPropertyAtPut(JSRegExp::kGlobalFieldIndex, global);
1460 regexp->InObjectPropertyAtPut(JSRegExp::kIgnoreCaseFieldIndex, ignoreCase);
1461 regexp->InObjectPropertyAtPut(JSRegExp::kMultilineFieldIndex, multiline);
1462 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
1463 Smi::FromInt(0),
1464 SKIP_WRITE_BARRIER);
1465 return regexp;
1466 }
1467
lrn@chromium.org303ada72010-10-27 09:33:13 +00001468 // Map has changed, so use generic, but slower, method. Since these
1469 // properties were all added as DONT_DELETE they must be present and
1470 // normal so no failures can be expected.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001471 PropertyAttributes final =
1472 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
1473 PropertyAttributes writable =
1474 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001475 MaybeObject* result;
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001476 result = regexp->SetLocalPropertyIgnoreAttributes(Heap::source_symbol(),
1477 source,
1478 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001479 ASSERT(!result->IsFailure());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001480 result = regexp->SetLocalPropertyIgnoreAttributes(Heap::global_symbol(),
1481 global,
1482 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001483 ASSERT(!result->IsFailure());
1484 result =
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001485 regexp->SetLocalPropertyIgnoreAttributes(Heap::ignore_case_symbol(),
1486 ignoreCase,
1487 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001488 ASSERT(!result->IsFailure());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001489 result = regexp->SetLocalPropertyIgnoreAttributes(Heap::multiline_symbol(),
1490 multiline,
1491 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001492 ASSERT(!result->IsFailure());
1493 result =
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001494 regexp->SetLocalPropertyIgnoreAttributes(Heap::last_index_symbol(),
1495 Smi::FromInt(0),
1496 writable);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001497 ASSERT(!result->IsFailure());
1498 USE(result);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001499 return regexp;
1500}
1501
1502
lrn@chromium.org303ada72010-10-27 09:33:13 +00001503static MaybeObject* Runtime_FinishArrayPrototypeSetup(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001504 HandleScope scope;
1505 ASSERT(args.length() == 1);
1506 CONVERT_ARG_CHECKED(JSArray, prototype, 0);
1507 // This is necessary to enable fast checks for absence of elements
1508 // on Array.prototype and below.
1509 prototype->set_elements(Heap::empty_fixed_array());
1510 return Smi::FromInt(0);
1511}
1512
1513
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001514static Handle<JSFunction> InstallBuiltin(Handle<JSObject> holder,
1515 const char* name,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001516 Builtins::Name builtin_name) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001517 Handle<String> key = Factory::LookupAsciiSymbol(name);
1518 Handle<Code> code(Builtins::builtin(builtin_name));
1519 Handle<JSFunction> optimized = Factory::NewFunction(key,
1520 JS_OBJECT_TYPE,
1521 JSObject::kHeaderSize,
1522 code,
1523 false);
1524 optimized->shared()->DontAdaptArguments();
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001525 SetProperty(holder, key, optimized, NONE);
1526 return optimized;
1527}
1528
1529
lrn@chromium.org303ada72010-10-27 09:33:13 +00001530static MaybeObject* Runtime_SpecialArrayFunctions(Arguments args) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001531 HandleScope scope;
1532 ASSERT(args.length() == 1);
1533 CONVERT_ARG_CHECKED(JSObject, holder, 0);
1534
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001535 InstallBuiltin(holder, "pop", Builtins::ArrayPop);
1536 InstallBuiltin(holder, "push", Builtins::ArrayPush);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001537 InstallBuiltin(holder, "shift", Builtins::ArrayShift);
1538 InstallBuiltin(holder, "unshift", Builtins::ArrayUnshift);
1539 InstallBuiltin(holder, "slice", Builtins::ArraySlice);
1540 InstallBuiltin(holder, "splice", Builtins::ArraySplice);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001541 InstallBuiltin(holder, "concat", Builtins::ArrayConcat);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001542
1543 return *holder;
1544}
1545
1546
lrn@chromium.org303ada72010-10-27 09:33:13 +00001547static MaybeObject* Runtime_GetGlobalReceiver(Arguments args) {
ager@chromium.org357bf652010-04-12 11:30:10 +00001548 // Returns a real global receiver, not one of builtins object.
1549 Context* global_context = Top::context()->global()->global_context();
1550 return global_context->global()->global_receiver();
1551}
1552
1553
lrn@chromium.org303ada72010-10-27 09:33:13 +00001554static MaybeObject* Runtime_MaterializeRegExpLiteral(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001555 HandleScope scope;
1556 ASSERT(args.length() == 4);
1557 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
1558 int index = Smi::cast(args[1])->value();
1559 Handle<String> pattern = args.at<String>(2);
1560 Handle<String> flags = args.at<String>(3);
1561
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001562 // Get the RegExp function from the context in the literals array.
1563 // This is the RegExp function from the context in which the
1564 // function was created. We do not use the RegExp function from the
1565 // current global context because this might be the RegExp function
1566 // from another context which we should not have access to.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001567 Handle<JSFunction> constructor =
ager@chromium.org236ad962008-09-25 09:45:57 +00001568 Handle<JSFunction>(
1569 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001570 // Compute the regular expression literal.
1571 bool has_pending_exception;
1572 Handle<Object> regexp =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001573 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
1574 &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001575 if (has_pending_exception) {
1576 ASSERT(Top::has_pending_exception());
1577 return Failure::Exception();
1578 }
1579 literals->set(index, *regexp);
1580 return *regexp;
1581}
1582
1583
lrn@chromium.org303ada72010-10-27 09:33:13 +00001584static MaybeObject* Runtime_FunctionGetName(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001585 NoHandleAllocation ha;
1586 ASSERT(args.length() == 1);
1587
1588 CONVERT_CHECKED(JSFunction, f, args[0]);
1589 return f->shared()->name();
1590}
1591
1592
lrn@chromium.org303ada72010-10-27 09:33:13 +00001593static MaybeObject* Runtime_FunctionSetName(Arguments args) {
ager@chromium.org236ad962008-09-25 09:45:57 +00001594 NoHandleAllocation ha;
1595 ASSERT(args.length() == 2);
1596
1597 CONVERT_CHECKED(JSFunction, f, args[0]);
1598 CONVERT_CHECKED(String, name, args[1]);
1599 f->shared()->set_name(name);
1600 return Heap::undefined_value();
1601}
1602
1603
lrn@chromium.org303ada72010-10-27 09:33:13 +00001604static MaybeObject* Runtime_FunctionRemovePrototype(Arguments args) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001605 NoHandleAllocation ha;
1606 ASSERT(args.length() == 1);
1607
1608 CONVERT_CHECKED(JSFunction, f, args[0]);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001609 Object* obj;
1610 { MaybeObject* maybe_obj = f->RemovePrototype();
1611 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1612 }
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001613
1614 return Heap::undefined_value();
1615}
1616
1617
lrn@chromium.org303ada72010-10-27 09:33:13 +00001618static MaybeObject* Runtime_FunctionGetScript(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001619 HandleScope scope;
1620 ASSERT(args.length() == 1);
1621
1622 CONVERT_CHECKED(JSFunction, fun, args[0]);
1623 Handle<Object> script = Handle<Object>(fun->shared()->script());
1624 if (!script->IsScript()) return Heap::undefined_value();
1625
1626 return *GetScriptWrapper(Handle<Script>::cast(script));
1627}
1628
1629
lrn@chromium.org303ada72010-10-27 09:33:13 +00001630static MaybeObject* Runtime_FunctionGetSourceCode(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001631 NoHandleAllocation ha;
1632 ASSERT(args.length() == 1);
1633
1634 CONVERT_CHECKED(JSFunction, f, args[0]);
1635 return f->shared()->GetSourceCode();
1636}
1637
1638
lrn@chromium.org303ada72010-10-27 09:33:13 +00001639static MaybeObject* Runtime_FunctionGetScriptSourcePosition(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001640 NoHandleAllocation ha;
1641 ASSERT(args.length() == 1);
1642
1643 CONVERT_CHECKED(JSFunction, fun, args[0]);
1644 int pos = fun->shared()->start_position();
1645 return Smi::FromInt(pos);
1646}
1647
1648
lrn@chromium.org303ada72010-10-27 09:33:13 +00001649static MaybeObject* Runtime_FunctionGetPositionForOffset(Arguments args) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001650 ASSERT(args.length() == 2);
1651
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001652 CONVERT_CHECKED(Code, code, args[0]);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001653 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
1654
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001655 RUNTIME_ASSERT(0 <= offset && offset < code->Size());
1656
1657 Address pc = code->address() + offset;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001658 return Smi::FromInt(code->SourcePosition(pc));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001659}
1660
1661
1662
lrn@chromium.org303ada72010-10-27 09:33:13 +00001663static MaybeObject* Runtime_FunctionSetInstanceClassName(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001664 NoHandleAllocation ha;
1665 ASSERT(args.length() == 2);
1666
1667 CONVERT_CHECKED(JSFunction, fun, args[0]);
1668 CONVERT_CHECKED(String, name, args[1]);
1669 fun->SetInstanceClassName(name);
1670 return Heap::undefined_value();
1671}
1672
1673
lrn@chromium.org303ada72010-10-27 09:33:13 +00001674static MaybeObject* Runtime_FunctionSetLength(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001675 NoHandleAllocation ha;
1676 ASSERT(args.length() == 2);
1677
1678 CONVERT_CHECKED(JSFunction, fun, args[0]);
1679 CONVERT_CHECKED(Smi, length, args[1]);
1680 fun->shared()->set_length(length->value());
1681 return length;
1682}
1683
1684
lrn@chromium.org303ada72010-10-27 09:33:13 +00001685static MaybeObject* Runtime_FunctionSetPrototype(Arguments args) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001686 NoHandleAllocation ha;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001687 ASSERT(args.length() == 2);
1688
1689 CONVERT_CHECKED(JSFunction, fun, args[0]);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001690 ASSERT(fun->should_have_prototype());
lrn@chromium.org303ada72010-10-27 09:33:13 +00001691 Object* obj;
1692 { MaybeObject* maybe_obj =
1693 Accessors::FunctionSetPrototype(fun, args[1], NULL);
1694 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1695 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001696 return args[0]; // return TOS
1697}
1698
1699
lrn@chromium.org303ada72010-10-27 09:33:13 +00001700static MaybeObject* Runtime_FunctionIsAPIFunction(Arguments args) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001701 NoHandleAllocation ha;
1702 ASSERT(args.length() == 1);
1703
1704 CONVERT_CHECKED(JSFunction, f, args[0]);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001705 return f->shared()->IsApiFunction() ? Heap::true_value()
1706 : Heap::false_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001707}
1708
lrn@chromium.org303ada72010-10-27 09:33:13 +00001709static MaybeObject* Runtime_FunctionIsBuiltin(Arguments args) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001710 NoHandleAllocation ha;
1711 ASSERT(args.length() == 1);
1712
1713 CONVERT_CHECKED(JSFunction, f, args[0]);
1714 return f->IsBuiltin() ? Heap::true_value() : Heap::false_value();
1715}
1716
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001717
lrn@chromium.org303ada72010-10-27 09:33:13 +00001718static MaybeObject* Runtime_SetCode(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001719 HandleScope scope;
1720 ASSERT(args.length() == 2);
1721
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001722 CONVERT_ARG_CHECKED(JSFunction, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001723 Handle<Object> code = args.at<Object>(1);
1724
1725 Handle<Context> context(target->context());
1726
1727 if (!code->IsNull()) {
1728 RUNTIME_ASSERT(code->IsJSFunction());
1729 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001730 Handle<SharedFunctionInfo> shared(fun->shared());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001731
1732 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001733 return Failure::Exception();
1734 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001735 // Since we don't store the source for this we should never
1736 // optimize this.
1737 shared->code()->set_optimizable(false);
1738
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001739 // Set the code, scope info, formal parameter count,
1740 // and the length of the target function.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00001741 target->shared()->set_code(shared->code());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001742 target->ReplaceCode(shared->code());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001743 target->shared()->set_scope_info(shared->scope_info());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001744 target->shared()->set_length(shared->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001745 target->shared()->set_formal_parameter_count(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001746 shared->formal_parameter_count());
ager@chromium.org7c537e22008-10-16 08:43:32 +00001747 // Set the source code of the target function to undefined.
1748 // SetCode is only used for built-in constructors like String,
1749 // Array, and Object, and some web code
1750 // doesn't like seeing source code for constructors.
1751 target->shared()->set_script(Heap::undefined_value());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001752 target->shared()->code()->set_optimizable(false);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001753 // Clear the optimization hints related to the compiled code as these are no
1754 // longer valid when the code is overwritten.
1755 target->shared()->ClearThisPropertyAssignmentsInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001756 context = Handle<Context>(fun->context());
1757
1758 // Make sure we get a fresh copy of the literal vector to avoid
1759 // cross context contamination.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001760 int number_of_literals = fun->NumberOfLiterals();
1761 Handle<FixedArray> literals =
1762 Factory::NewFixedArray(number_of_literals, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001763 if (number_of_literals > 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001764 // Insert the object, regexp and array functions in the literals
1765 // array prefix. These are the functions that will be used when
1766 // creating object, regexp and array literals.
ager@chromium.org236ad962008-09-25 09:45:57 +00001767 literals->set(JSFunction::kLiteralGlobalContextIndex,
1768 context->global_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001769 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001770 // It's okay to skip the write barrier here because the literals
1771 // are guaranteed to be in old space.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001772 target->set_literals(*literals, SKIP_WRITE_BARRIER);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001773 target->set_next_function_link(Heap::undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001774 }
1775
1776 target->set_context(*context);
1777 return *target;
1778}
1779
1780
lrn@chromium.org303ada72010-10-27 09:33:13 +00001781static MaybeObject* Runtime_SetExpectedNumberOfProperties(Arguments args) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001782 HandleScope scope;
1783 ASSERT(args.length() == 2);
1784 CONVERT_ARG_CHECKED(JSFunction, function, 0);
1785 CONVERT_SMI_CHECKED(num, args[1]);
1786 RUNTIME_ASSERT(num >= 0);
1787 SetExpectedNofProperties(function, num);
1788 return Heap::undefined_value();
1789}
1790
1791
lrn@chromium.org303ada72010-10-27 09:33:13 +00001792MUST_USE_RESULT static MaybeObject* CharFromCode(Object* char_code) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001793 uint32_t code;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001794 if (char_code->ToArrayIndex(&code)) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001795 if (code <= 0xffff) {
1796 return Heap::LookupSingleCharacterStringFromCode(code);
1797 }
1798 }
1799 return Heap::empty_string();
1800}
1801
1802
lrn@chromium.org303ada72010-10-27 09:33:13 +00001803static MaybeObject* Runtime_StringCharCodeAt(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001804 NoHandleAllocation ha;
1805 ASSERT(args.length() == 2);
1806
1807 CONVERT_CHECKED(String, subject, args[0]);
1808 Object* index = args[1];
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001809 RUNTIME_ASSERT(index->IsNumber());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001810
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001811 uint32_t i = 0;
1812 if (index->IsSmi()) {
1813 int value = Smi::cast(index)->value();
1814 if (value < 0) return Heap::nan_value();
1815 i = value;
1816 } else {
1817 ASSERT(index->IsHeapNumber());
1818 double value = HeapNumber::cast(index)->value();
1819 i = static_cast<uint32_t>(DoubleToInteger(value));
kasperl@chromium.org74e4e5e2010-01-25 10:15:52 +00001820 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001821
1822 // Flatten the string. If someone wants to get a char at an index
1823 // in a cons string, it is likely that more indices will be
1824 // accessed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001825 Object* flat;
1826 { MaybeObject* maybe_flat = subject->TryFlatten();
1827 if (!maybe_flat->ToObject(&flat)) return maybe_flat;
1828 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001829 subject = String::cast(flat);
1830
1831 if (i >= static_cast<uint32_t>(subject->length())) {
1832 return Heap::nan_value();
1833 }
1834
1835 return Smi::FromInt(subject->Get(i));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001836}
1837
1838
lrn@chromium.org303ada72010-10-27 09:33:13 +00001839static MaybeObject* Runtime_CharFromCode(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001840 NoHandleAllocation ha;
1841 ASSERT(args.length() == 1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001842 return CharFromCode(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001843}
1844
lrn@chromium.org25156de2010-04-06 13:10:27 +00001845
1846class FixedArrayBuilder {
1847 public:
1848 explicit FixedArrayBuilder(int initial_capacity)
1849 : array_(Factory::NewFixedArrayWithHoles(initial_capacity)),
1850 length_(0) {
1851 // Require a non-zero initial size. Ensures that doubling the size to
1852 // extend the array will work.
1853 ASSERT(initial_capacity > 0);
1854 }
1855
1856 explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
1857 : array_(backing_store),
1858 length_(0) {
1859 // Require a non-zero initial size. Ensures that doubling the size to
1860 // extend the array will work.
1861 ASSERT(backing_store->length() > 0);
1862 }
1863
1864 bool HasCapacity(int elements) {
1865 int length = array_->length();
1866 int required_length = length_ + elements;
1867 return (length >= required_length);
1868 }
1869
1870 void EnsureCapacity(int elements) {
1871 int length = array_->length();
1872 int required_length = length_ + elements;
1873 if (length < required_length) {
1874 int new_length = length;
1875 do {
1876 new_length *= 2;
1877 } while (new_length < required_length);
1878 Handle<FixedArray> extended_array =
1879 Factory::NewFixedArrayWithHoles(new_length);
1880 array_->CopyTo(0, *extended_array, 0, length_);
1881 array_ = extended_array;
1882 }
1883 }
1884
1885 void Add(Object* value) {
1886 ASSERT(length_ < capacity());
1887 array_->set(length_, value);
1888 length_++;
1889 }
1890
1891 void Add(Smi* value) {
1892 ASSERT(length_ < capacity());
1893 array_->set(length_, value);
1894 length_++;
1895 }
1896
1897 Handle<FixedArray> array() {
1898 return array_;
1899 }
1900
1901 int length() {
1902 return length_;
1903 }
1904
1905 int capacity() {
1906 return array_->length();
1907 }
1908
1909 Handle<JSArray> ToJSArray() {
1910 Handle<JSArray> result_array = Factory::NewJSArrayWithElements(array_);
1911 result_array->set_length(Smi::FromInt(length_));
1912 return result_array;
1913 }
1914
1915 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
1916 target_array->set_elements(*array_);
1917 target_array->set_length(Smi::FromInt(length_));
1918 return target_array;
1919 }
1920
1921 private:
1922 Handle<FixedArray> array_;
1923 int length_;
1924};
1925
1926
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001927// Forward declarations.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001928const int kStringBuilderConcatHelperLengthBits = 11;
1929const int kStringBuilderConcatHelperPositionBits = 19;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001930
1931template <typename schar>
1932static inline void StringBuilderConcatHelper(String*,
1933 schar*,
1934 FixedArray*,
1935 int);
1936
lrn@chromium.org25156de2010-04-06 13:10:27 +00001937typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
1938 StringBuilderSubstringLength;
1939typedef BitField<int,
1940 kStringBuilderConcatHelperLengthBits,
1941 kStringBuilderConcatHelperPositionBits>
1942 StringBuilderSubstringPosition;
1943
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001944
1945class ReplacementStringBuilder {
1946 public:
1947 ReplacementStringBuilder(Handle<String> subject, int estimated_part_count)
lrn@chromium.org25156de2010-04-06 13:10:27 +00001948 : array_builder_(estimated_part_count),
1949 subject_(subject),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001950 character_count_(0),
ager@chromium.org5ec48922009-05-05 07:25:34 +00001951 is_ascii_(subject->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001952 // Require a non-zero initial size. Ensures that doubling the size to
1953 // extend the array will work.
1954 ASSERT(estimated_part_count > 0);
1955 }
1956
lrn@chromium.org25156de2010-04-06 13:10:27 +00001957 static inline void AddSubjectSlice(FixedArrayBuilder* builder,
1958 int from,
1959 int to) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001960 ASSERT(from >= 0);
1961 int length = to - from;
1962 ASSERT(length > 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001963 if (StringBuilderSubstringLength::is_valid(length) &&
1964 StringBuilderSubstringPosition::is_valid(from)) {
1965 int encoded_slice = StringBuilderSubstringLength::encode(length) |
1966 StringBuilderSubstringPosition::encode(from);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001967 builder->Add(Smi::FromInt(encoded_slice));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001968 } else {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001969 // Otherwise encode as two smis.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001970 builder->Add(Smi::FromInt(-length));
1971 builder->Add(Smi::FromInt(from));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001972 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00001973 }
1974
1975
1976 void EnsureCapacity(int elements) {
1977 array_builder_.EnsureCapacity(elements);
1978 }
1979
1980
1981 void AddSubjectSlice(int from, int to) {
1982 AddSubjectSlice(&array_builder_, from, to);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001983 IncrementCharacterCount(to - from);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001984 }
1985
1986
1987 void AddString(Handle<String> string) {
1988 int length = string->length();
1989 ASSERT(length > 0);
1990 AddElement(*string);
ager@chromium.org5ec48922009-05-05 07:25:34 +00001991 if (!string->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001992 is_ascii_ = false;
1993 }
1994 IncrementCharacterCount(length);
1995 }
1996
1997
1998 Handle<String> ToString() {
lrn@chromium.org25156de2010-04-06 13:10:27 +00001999 if (array_builder_.length() == 0) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002000 return Factory::empty_string();
2001 }
2002
2003 Handle<String> joined_string;
2004 if (is_ascii_) {
2005 joined_string = NewRawAsciiString(character_count_);
2006 AssertNoAllocation no_alloc;
2007 SeqAsciiString* seq = SeqAsciiString::cast(*joined_string);
2008 char* char_buffer = seq->GetChars();
2009 StringBuilderConcatHelper(*subject_,
2010 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002011 *array_builder_.array(),
2012 array_builder_.length());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002013 } else {
2014 // Non-ASCII.
2015 joined_string = NewRawTwoByteString(character_count_);
2016 AssertNoAllocation no_alloc;
2017 SeqTwoByteString* seq = SeqTwoByteString::cast(*joined_string);
2018 uc16* char_buffer = seq->GetChars();
2019 StringBuilderConcatHelper(*subject_,
2020 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002021 *array_builder_.array(),
2022 array_builder_.length());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002023 }
2024 return joined_string;
2025 }
2026
2027
2028 void IncrementCharacterCount(int by) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002029 if (character_count_ > String::kMaxLength - by) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002030 V8::FatalProcessOutOfMemory("String.replace result too large.");
2031 }
2032 character_count_ += by;
2033 }
2034
lrn@chromium.org25156de2010-04-06 13:10:27 +00002035 Handle<JSArray> GetParts() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002036 return array_builder_.ToJSArray();
lrn@chromium.org25156de2010-04-06 13:10:27 +00002037 }
kmillikin@chromium.orgd9825192010-03-30 08:36:16 +00002038
lrn@chromium.org25156de2010-04-06 13:10:27 +00002039 private:
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002040 Handle<String> NewRawAsciiString(int size) {
2041 CALL_HEAP_FUNCTION(Heap::AllocateRawAsciiString(size), String);
2042 }
2043
2044
2045 Handle<String> NewRawTwoByteString(int size) {
2046 CALL_HEAP_FUNCTION(Heap::AllocateRawTwoByteString(size), String);
2047 }
2048
2049
2050 void AddElement(Object* element) {
2051 ASSERT(element->IsSmi() || element->IsString());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002052 ASSERT(array_builder_.capacity() > array_builder_.length());
2053 array_builder_.Add(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002054 }
2055
lrn@chromium.org25156de2010-04-06 13:10:27 +00002056 FixedArrayBuilder array_builder_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002057 Handle<String> subject_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002058 int character_count_;
2059 bool is_ascii_;
2060};
2061
2062
2063class CompiledReplacement {
2064 public:
2065 CompiledReplacement()
2066 : parts_(1), replacement_substrings_(0) {}
2067
2068 void Compile(Handle<String> replacement,
2069 int capture_count,
2070 int subject_length);
2071
2072 void Apply(ReplacementStringBuilder* builder,
2073 int match_from,
2074 int match_to,
2075 Handle<JSArray> last_match_info);
2076
2077 // Number of distinct parts of the replacement pattern.
2078 int parts() {
2079 return parts_.length();
2080 }
2081 private:
2082 enum PartType {
2083 SUBJECT_PREFIX = 1,
2084 SUBJECT_SUFFIX,
2085 SUBJECT_CAPTURE,
2086 REPLACEMENT_SUBSTRING,
2087 REPLACEMENT_STRING,
2088
2089 NUMBER_OF_PART_TYPES
2090 };
2091
2092 struct ReplacementPart {
2093 static inline ReplacementPart SubjectMatch() {
2094 return ReplacementPart(SUBJECT_CAPTURE, 0);
2095 }
2096 static inline ReplacementPart SubjectCapture(int capture_index) {
2097 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
2098 }
2099 static inline ReplacementPart SubjectPrefix() {
2100 return ReplacementPart(SUBJECT_PREFIX, 0);
2101 }
2102 static inline ReplacementPart SubjectSuffix(int subject_length) {
2103 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
2104 }
2105 static inline ReplacementPart ReplacementString() {
2106 return ReplacementPart(REPLACEMENT_STRING, 0);
2107 }
2108 static inline ReplacementPart ReplacementSubString(int from, int to) {
2109 ASSERT(from >= 0);
2110 ASSERT(to > from);
2111 return ReplacementPart(-from, to);
2112 }
2113
2114 // If tag <= 0 then it is the negation of a start index of a substring of
2115 // the replacement pattern, otherwise it's a value from PartType.
2116 ReplacementPart(int tag, int data)
2117 : tag(tag), data(data) {
2118 // Must be non-positive or a PartType value.
2119 ASSERT(tag < NUMBER_OF_PART_TYPES);
2120 }
2121 // Either a value of PartType or a non-positive number that is
2122 // the negation of an index into the replacement string.
2123 int tag;
2124 // The data value's interpretation depends on the value of tag:
2125 // tag == SUBJECT_PREFIX ||
2126 // tag == SUBJECT_SUFFIX: data is unused.
2127 // tag == SUBJECT_CAPTURE: data is the number of the capture.
2128 // tag == REPLACEMENT_SUBSTRING ||
2129 // tag == REPLACEMENT_STRING: data is index into array of substrings
2130 // of the replacement string.
2131 // tag <= 0: Temporary representation of the substring of the replacement
2132 // string ranging over -tag .. data.
2133 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
2134 // substring objects.
2135 int data;
2136 };
2137
2138 template<typename Char>
2139 static void ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
2140 Vector<Char> characters,
2141 int capture_count,
2142 int subject_length) {
2143 int length = characters.length();
2144 int last = 0;
2145 for (int i = 0; i < length; i++) {
2146 Char c = characters[i];
2147 if (c == '$') {
2148 int next_index = i + 1;
2149 if (next_index == length) { // No next character!
2150 break;
2151 }
2152 Char c2 = characters[next_index];
2153 switch (c2) {
2154 case '$':
2155 if (i > last) {
2156 // There is a substring before. Include the first "$".
2157 parts->Add(ReplacementPart::ReplacementSubString(last, next_index));
2158 last = next_index + 1; // Continue after the second "$".
2159 } else {
2160 // Let the next substring start with the second "$".
2161 last = next_index;
2162 }
2163 i = next_index;
2164 break;
2165 case '`':
2166 if (i > last) {
2167 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2168 }
2169 parts->Add(ReplacementPart::SubjectPrefix());
2170 i = next_index;
2171 last = i + 1;
2172 break;
2173 case '\'':
2174 if (i > last) {
2175 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2176 }
2177 parts->Add(ReplacementPart::SubjectSuffix(subject_length));
2178 i = next_index;
2179 last = i + 1;
2180 break;
2181 case '&':
2182 if (i > last) {
2183 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2184 }
2185 parts->Add(ReplacementPart::SubjectMatch());
2186 i = next_index;
2187 last = i + 1;
2188 break;
2189 case '0':
2190 case '1':
2191 case '2':
2192 case '3':
2193 case '4':
2194 case '5':
2195 case '6':
2196 case '7':
2197 case '8':
2198 case '9': {
2199 int capture_ref = c2 - '0';
2200 if (capture_ref > capture_count) {
2201 i = next_index;
2202 continue;
2203 }
2204 int second_digit_index = next_index + 1;
2205 if (second_digit_index < length) {
2206 // Peek ahead to see if we have two digits.
2207 Char c3 = characters[second_digit_index];
2208 if ('0' <= c3 && c3 <= '9') { // Double digits.
2209 int double_digit_ref = capture_ref * 10 + c3 - '0';
2210 if (double_digit_ref <= capture_count) {
2211 next_index = second_digit_index;
2212 capture_ref = double_digit_ref;
2213 }
2214 }
2215 }
2216 if (capture_ref > 0) {
2217 if (i > last) {
2218 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2219 }
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002220 ASSERT(capture_ref <= capture_count);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002221 parts->Add(ReplacementPart::SubjectCapture(capture_ref));
2222 last = next_index + 1;
2223 }
2224 i = next_index;
2225 break;
2226 }
2227 default:
2228 i = next_index;
2229 break;
2230 }
2231 }
2232 }
2233 if (length > last) {
2234 if (last == 0) {
2235 parts->Add(ReplacementPart::ReplacementString());
2236 } else {
2237 parts->Add(ReplacementPart::ReplacementSubString(last, length));
2238 }
2239 }
2240 }
2241
2242 ZoneList<ReplacementPart> parts_;
2243 ZoneList<Handle<String> > replacement_substrings_;
2244};
2245
2246
2247void CompiledReplacement::Compile(Handle<String> replacement,
2248 int capture_count,
2249 int subject_length) {
2250 ASSERT(replacement->IsFlat());
ager@chromium.org5ec48922009-05-05 07:25:34 +00002251 if (replacement->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002252 AssertNoAllocation no_alloc;
2253 ParseReplacementPattern(&parts_,
2254 replacement->ToAsciiVector(),
2255 capture_count,
2256 subject_length);
2257 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00002258 ASSERT(replacement->IsTwoByteRepresentation());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002259 AssertNoAllocation no_alloc;
2260
2261 ParseReplacementPattern(&parts_,
2262 replacement->ToUC16Vector(),
2263 capture_count,
2264 subject_length);
2265 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002266 // Find substrings of replacement string and create them as String objects.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002267 int substring_index = 0;
2268 for (int i = 0, n = parts_.length(); i < n; i++) {
2269 int tag = parts_[i].tag;
2270 if (tag <= 0) { // A replacement string slice.
2271 int from = -tag;
2272 int to = parts_[i].data;
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002273 replacement_substrings_.Add(Factory::NewSubString(replacement, from, to));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002274 parts_[i].tag = REPLACEMENT_SUBSTRING;
2275 parts_[i].data = substring_index;
2276 substring_index++;
2277 } else if (tag == REPLACEMENT_STRING) {
2278 replacement_substrings_.Add(replacement);
2279 parts_[i].data = substring_index;
2280 substring_index++;
2281 }
2282 }
2283}
2284
2285
2286void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
2287 int match_from,
2288 int match_to,
2289 Handle<JSArray> last_match_info) {
2290 for (int i = 0, n = parts_.length(); i < n; i++) {
2291 ReplacementPart part = parts_[i];
2292 switch (part.tag) {
2293 case SUBJECT_PREFIX:
2294 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
2295 break;
2296 case SUBJECT_SUFFIX: {
2297 int subject_length = part.data;
2298 if (match_to < subject_length) {
2299 builder->AddSubjectSlice(match_to, subject_length);
2300 }
2301 break;
2302 }
2303 case SUBJECT_CAPTURE: {
2304 int capture = part.data;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002305 FixedArray* match_info = FixedArray::cast(last_match_info->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002306 int from = RegExpImpl::GetCapture(match_info, capture * 2);
2307 int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1);
2308 if (from >= 0 && to > from) {
2309 builder->AddSubjectSlice(from, to);
2310 }
2311 break;
2312 }
2313 case REPLACEMENT_SUBSTRING:
2314 case REPLACEMENT_STRING:
2315 builder->AddString(replacement_substrings_[part.data]);
2316 break;
2317 default:
2318 UNREACHABLE();
2319 }
2320 }
2321}
2322
2323
2324
lrn@chromium.org303ada72010-10-27 09:33:13 +00002325MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
2326 String* subject,
2327 JSRegExp* regexp,
2328 String* replacement,
2329 JSArray* last_match_info) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002330 ASSERT(subject->IsFlat());
2331 ASSERT(replacement->IsFlat());
2332
2333 HandleScope handles;
2334
2335 int length = subject->length();
2336 Handle<String> subject_handle(subject);
2337 Handle<JSRegExp> regexp_handle(regexp);
2338 Handle<String> replacement_handle(replacement);
2339 Handle<JSArray> last_match_info_handle(last_match_info);
2340 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2341 subject_handle,
2342 0,
2343 last_match_info_handle);
2344 if (match.is_null()) {
2345 return Failure::Exception();
2346 }
2347 if (match->IsNull()) {
2348 return *subject_handle;
2349 }
2350
2351 int capture_count = regexp_handle->CaptureCount();
2352
2353 // CompiledReplacement uses zone allocation.
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00002354 CompilationZoneScope zone(DELETE_ON_EXIT);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002355 CompiledReplacement compiled_replacement;
2356 compiled_replacement.Compile(replacement_handle,
2357 capture_count,
2358 length);
2359
2360 bool is_global = regexp_handle->GetFlags().is_global();
2361
2362 // Guessing the number of parts that the final result string is built
2363 // from. Global regexps can match any number of times, so we guess
2364 // conservatively.
2365 int expected_parts =
2366 (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1;
2367 ReplacementStringBuilder builder(subject_handle, expected_parts);
2368
2369 // Index of end of last match.
2370 int prev = 0;
2371
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002372 // Number of parts added by compiled replacement plus preceeding
2373 // string and possibly suffix after last match. It is possible for
2374 // all components to use two elements when encoded as two smis.
2375 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002376 bool matched = true;
2377 do {
2378 ASSERT(last_match_info_handle->HasFastElements());
2379 // Increase the capacity of the builder before entering local handle-scope,
2380 // so its internal buffer can safely allocate a new handle if it grows.
2381 builder.EnsureCapacity(parts_added_per_loop);
2382
2383 HandleScope loop_scope;
2384 int start, end;
2385 {
2386 AssertNoAllocation match_info_array_is_not_in_a_handle;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002387 FixedArray* match_info_array =
2388 FixedArray::cast(last_match_info_handle->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002389
2390 ASSERT_EQ(capture_count * 2 + 2,
2391 RegExpImpl::GetLastCaptureCount(match_info_array));
2392 start = RegExpImpl::GetCapture(match_info_array, 0);
2393 end = RegExpImpl::GetCapture(match_info_array, 1);
2394 }
2395
2396 if (prev < start) {
2397 builder.AddSubjectSlice(prev, start);
2398 }
2399 compiled_replacement.Apply(&builder,
2400 start,
2401 end,
2402 last_match_info_handle);
2403 prev = end;
2404
2405 // Only continue checking for global regexps.
2406 if (!is_global) break;
2407
2408 // Continue from where the match ended, unless it was an empty match.
2409 int next = end;
2410 if (start == end) {
2411 next = end + 1;
2412 if (next > length) break;
2413 }
2414
2415 match = RegExpImpl::Exec(regexp_handle,
2416 subject_handle,
2417 next,
2418 last_match_info_handle);
2419 if (match.is_null()) {
2420 return Failure::Exception();
2421 }
2422 matched = !match->IsNull();
2423 } while (matched);
2424
2425 if (prev < length) {
2426 builder.AddSubjectSlice(prev, length);
2427 }
2428
2429 return *(builder.ToString());
2430}
2431
2432
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002433template <typename ResultSeqString>
lrn@chromium.org303ada72010-10-27 09:33:13 +00002434MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
2435 String* subject,
2436 JSRegExp* regexp,
2437 JSArray* last_match_info) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002438 ASSERT(subject->IsFlat());
2439
2440 HandleScope handles;
2441
2442 Handle<String> subject_handle(subject);
2443 Handle<JSRegExp> regexp_handle(regexp);
2444 Handle<JSArray> last_match_info_handle(last_match_info);
2445 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2446 subject_handle,
2447 0,
2448 last_match_info_handle);
2449 if (match.is_null()) return Failure::Exception();
2450 if (match->IsNull()) return *subject_handle;
2451
2452 ASSERT(last_match_info_handle->HasFastElements());
2453
2454 HandleScope loop_scope;
2455 int start, end;
2456 {
2457 AssertNoAllocation match_info_array_is_not_in_a_handle;
2458 FixedArray* match_info_array =
2459 FixedArray::cast(last_match_info_handle->elements());
2460
2461 start = RegExpImpl::GetCapture(match_info_array, 0);
2462 end = RegExpImpl::GetCapture(match_info_array, 1);
2463 }
2464
2465 int length = subject->length();
2466 int new_length = length - (end - start);
2467 if (new_length == 0) {
2468 return Heap::empty_string();
2469 }
2470 Handle<ResultSeqString> answer;
2471 if (ResultSeqString::kHasAsciiEncoding) {
2472 answer =
2473 Handle<ResultSeqString>::cast(Factory::NewRawAsciiString(new_length));
2474 } else {
2475 answer =
2476 Handle<ResultSeqString>::cast(Factory::NewRawTwoByteString(new_length));
2477 }
2478
2479 // If the regexp isn't global, only match once.
2480 if (!regexp_handle->GetFlags().is_global()) {
2481 if (start > 0) {
2482 String::WriteToFlat(*subject_handle,
2483 answer->GetChars(),
2484 0,
2485 start);
2486 }
2487 if (end < length) {
2488 String::WriteToFlat(*subject_handle,
2489 answer->GetChars() + start,
2490 end,
2491 length);
2492 }
2493 return *answer;
2494 }
2495
2496 int prev = 0; // Index of end of last match.
2497 int next = 0; // Start of next search (prev unless last match was empty).
2498 int position = 0;
2499
2500 do {
2501 if (prev < start) {
2502 // Add substring subject[prev;start] to answer string.
2503 String::WriteToFlat(*subject_handle,
2504 answer->GetChars() + position,
2505 prev,
2506 start);
2507 position += start - prev;
2508 }
2509 prev = end;
2510 next = end;
2511 // Continue from where the match ended, unless it was an empty match.
2512 if (start == end) {
2513 next++;
2514 if (next > length) break;
2515 }
2516 match = RegExpImpl::Exec(regexp_handle,
2517 subject_handle,
2518 next,
2519 last_match_info_handle);
2520 if (match.is_null()) return Failure::Exception();
2521 if (match->IsNull()) break;
2522
2523 ASSERT(last_match_info_handle->HasFastElements());
2524 HandleScope loop_scope;
2525 {
2526 AssertNoAllocation match_info_array_is_not_in_a_handle;
2527 FixedArray* match_info_array =
2528 FixedArray::cast(last_match_info_handle->elements());
2529 start = RegExpImpl::GetCapture(match_info_array, 0);
2530 end = RegExpImpl::GetCapture(match_info_array, 1);
2531 }
2532 } while (true);
2533
2534 if (prev < length) {
2535 // Add substring subject[prev;length] to answer string.
2536 String::WriteToFlat(*subject_handle,
2537 answer->GetChars() + position,
2538 prev,
2539 length);
2540 position += length - prev;
2541 }
2542
2543 if (position == 0) {
2544 return Heap::empty_string();
2545 }
2546
2547 // Shorten string and fill
2548 int string_size = ResultSeqString::SizeFor(position);
2549 int allocated_string_size = ResultSeqString::SizeFor(new_length);
2550 int delta = allocated_string_size - string_size;
2551
2552 answer->set_length(position);
2553 if (delta == 0) return *answer;
2554
2555 Address end_of_string = answer->address() + string_size;
2556 Heap::CreateFillerObjectAt(end_of_string, delta);
2557
2558 return *answer;
2559}
2560
2561
lrn@chromium.org303ada72010-10-27 09:33:13 +00002562static MaybeObject* Runtime_StringReplaceRegExpWithString(Arguments args) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002563 ASSERT(args.length() == 4);
2564
2565 CONVERT_CHECKED(String, subject, args[0]);
2566 if (!subject->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002567 Object* flat_subject;
2568 { MaybeObject* maybe_flat_subject = subject->TryFlatten();
2569 if (!maybe_flat_subject->ToObject(&flat_subject)) {
2570 return maybe_flat_subject;
2571 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002572 }
2573 subject = String::cast(flat_subject);
2574 }
2575
2576 CONVERT_CHECKED(String, replacement, args[2]);
2577 if (!replacement->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002578 Object* flat_replacement;
2579 { MaybeObject* maybe_flat_replacement = replacement->TryFlatten();
2580 if (!maybe_flat_replacement->ToObject(&flat_replacement)) {
2581 return maybe_flat_replacement;
2582 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002583 }
2584 replacement = String::cast(flat_replacement);
2585 }
2586
2587 CONVERT_CHECKED(JSRegExp, regexp, args[1]);
2588 CONVERT_CHECKED(JSArray, last_match_info, args[3]);
2589
2590 ASSERT(last_match_info->HasFastElements());
2591
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002592 if (replacement->length() == 0) {
2593 if (subject->HasOnlyAsciiChars()) {
2594 return StringReplaceRegExpWithEmptyString<SeqAsciiString>(
2595 subject, regexp, last_match_info);
2596 } else {
2597 return StringReplaceRegExpWithEmptyString<SeqTwoByteString>(
2598 subject, regexp, last_match_info);
2599 }
2600 }
2601
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002602 return StringReplaceRegExpWithString(subject,
2603 regexp,
2604 replacement,
2605 last_match_info);
2606}
2607
2608
ager@chromium.org7c537e22008-10-16 08:43:32 +00002609// Perform string match of pattern on subject, starting at start index.
2610// Caller must ensure that 0 <= start_index <= sub->length(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002611// and should check that pat->length() + start_index <= sub->length().
ager@chromium.org7c537e22008-10-16 08:43:32 +00002612int Runtime::StringMatch(Handle<String> sub,
2613 Handle<String> pat,
2614 int start_index) {
2615 ASSERT(0 <= start_index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002616 ASSERT(start_index <= sub->length());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002617
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00002618 int pattern_length = pat->length();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002619 if (pattern_length == 0) return start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002620
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002621 int subject_length = sub->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00002622 if (start_index + pattern_length > subject_length) return -1;
2623
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002624 if (!sub->IsFlat()) FlattenString(sub);
2625 if (!pat->IsFlat()) FlattenString(pat);
ager@chromium.org236ad962008-09-25 09:45:57 +00002626
ager@chromium.org7c537e22008-10-16 08:43:32 +00002627 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002628 // Extract flattened substrings of cons strings before determining asciiness.
2629 String* seq_sub = *sub;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002630 if (seq_sub->IsConsString()) seq_sub = ConsString::cast(seq_sub)->first();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002631 String* seq_pat = *pat;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002632 if (seq_pat->IsConsString()) seq_pat = ConsString::cast(seq_pat)->first();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002633
ager@chromium.org7c537e22008-10-16 08:43:32 +00002634 // dispatch on type of strings
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002635 if (seq_pat->IsAsciiRepresentation()) {
2636 Vector<const char> pat_vector = seq_pat->ToAsciiVector();
2637 if (seq_sub->IsAsciiRepresentation()) {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002638 return SearchString(seq_sub->ToAsciiVector(), pat_vector, start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00002639 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002640 return SearchString(seq_sub->ToUC16Vector(), pat_vector, start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00002641 }
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002642 Vector<const uc16> pat_vector = seq_pat->ToUC16Vector();
2643 if (seq_sub->IsAsciiRepresentation()) {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002644 return SearchString(seq_sub->ToAsciiVector(), pat_vector, start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002645 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002646 return SearchString(seq_sub->ToUC16Vector(), pat_vector, start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002647}
2648
2649
lrn@chromium.org303ada72010-10-27 09:33:13 +00002650static MaybeObject* Runtime_StringIndexOf(Arguments args) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00002651 HandleScope scope; // create a new handle scope
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002652 ASSERT(args.length() == 3);
2653
ager@chromium.org7c537e22008-10-16 08:43:32 +00002654 CONVERT_ARG_CHECKED(String, sub, 0);
2655 CONVERT_ARG_CHECKED(String, pat, 1);
2656
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002657 Object* index = args[2];
2658 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002659 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002660
ager@chromium.org870a0b62008-11-04 11:43:05 +00002661 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
ager@chromium.org7c537e22008-10-16 08:43:32 +00002662 int position = Runtime::StringMatch(sub, pat, start_index);
2663 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002664}
2665
2666
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002667template <typename schar, typename pchar>
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002668static int StringMatchBackwards(Vector<const schar> subject,
2669 Vector<const pchar> pattern,
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002670 int idx) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002671 int pattern_length = pattern.length();
2672 ASSERT(pattern_length >= 1);
2673 ASSERT(idx + pattern_length <= subject.length());
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002674
2675 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002676 for (int i = 0; i < pattern_length; i++) {
2677 uc16 c = pattern[i];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002678 if (c > String::kMaxAsciiCharCode) {
2679 return -1;
2680 }
2681 }
2682 }
2683
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002684 pchar pattern_first_char = pattern[0];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002685 for (int i = idx; i >= 0; i--) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002686 if (subject[i] != pattern_first_char) continue;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002687 int j = 1;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002688 while (j < pattern_length) {
2689 if (pattern[j] != subject[i+j]) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002690 break;
2691 }
2692 j++;
2693 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002694 if (j == pattern_length) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002695 return i;
2696 }
2697 }
2698 return -1;
2699}
2700
lrn@chromium.org303ada72010-10-27 09:33:13 +00002701static MaybeObject* Runtime_StringLastIndexOf(Arguments args) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002702 HandleScope scope; // create a new handle scope
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002703 ASSERT(args.length() == 3);
2704
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002705 CONVERT_ARG_CHECKED(String, sub, 0);
2706 CONVERT_ARG_CHECKED(String, pat, 1);
2707
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002708 Object* index = args[2];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002709 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002710 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002711
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002712 uint32_t pat_length = pat->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002713 uint32_t sub_length = sub->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002714
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002715 if (start_index + pat_length > sub_length) {
2716 start_index = sub_length - pat_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +00002717 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002718
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002719 if (pat_length == 0) {
2720 return Smi::FromInt(start_index);
2721 }
2722
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002723 if (!sub->IsFlat()) FlattenString(sub);
2724 if (!pat->IsFlat()) FlattenString(pat);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002725
2726 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
2727
2728 int position = -1;
2729
2730 if (pat->IsAsciiRepresentation()) {
2731 Vector<const char> pat_vector = pat->ToAsciiVector();
2732 if (sub->IsAsciiRepresentation()) {
2733 position = StringMatchBackwards(sub->ToAsciiVector(),
2734 pat_vector,
2735 start_index);
2736 } else {
2737 position = StringMatchBackwards(sub->ToUC16Vector(),
2738 pat_vector,
2739 start_index);
2740 }
2741 } else {
2742 Vector<const uc16> pat_vector = pat->ToUC16Vector();
2743 if (sub->IsAsciiRepresentation()) {
2744 position = StringMatchBackwards(sub->ToAsciiVector(),
2745 pat_vector,
2746 start_index);
2747 } else {
2748 position = StringMatchBackwards(sub->ToUC16Vector(),
2749 pat_vector,
2750 start_index);
2751 }
2752 }
2753
2754 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002755}
2756
2757
lrn@chromium.org303ada72010-10-27 09:33:13 +00002758static MaybeObject* Runtime_StringLocaleCompare(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002759 NoHandleAllocation ha;
2760 ASSERT(args.length() == 2);
2761
2762 CONVERT_CHECKED(String, str1, args[0]);
2763 CONVERT_CHECKED(String, str2, args[1]);
2764
2765 if (str1 == str2) return Smi::FromInt(0); // Equal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002766 int str1_length = str1->length();
2767 int str2_length = str2->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002768
2769 // Decide trivial cases without flattening.
2770 if (str1_length == 0) {
2771 if (str2_length == 0) return Smi::FromInt(0); // Equal.
2772 return Smi::FromInt(-str2_length);
2773 } else {
2774 if (str2_length == 0) return Smi::FromInt(str1_length);
2775 }
2776
2777 int end = str1_length < str2_length ? str1_length : str2_length;
2778
2779 // No need to flatten if we are going to find the answer on the first
2780 // character. At this point we know there is at least one character
2781 // in each string, due to the trivial case handling above.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002782 int d = str1->Get(0) - str2->Get(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002783 if (d != 0) return Smi::FromInt(d);
2784
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002785 str1->TryFlatten();
2786 str2->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002787
2788 static StringInputBuffer buf1;
2789 static StringInputBuffer buf2;
2790
2791 buf1.Reset(str1);
2792 buf2.Reset(str2);
2793
2794 for (int i = 0; i < end; i++) {
2795 uint16_t char1 = buf1.GetNext();
2796 uint16_t char2 = buf2.GetNext();
2797 if (char1 != char2) return Smi::FromInt(char1 - char2);
2798 }
2799
2800 return Smi::FromInt(str1_length - str2_length);
2801}
2802
2803
lrn@chromium.org303ada72010-10-27 09:33:13 +00002804static MaybeObject* Runtime_SubString(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002805 NoHandleAllocation ha;
2806 ASSERT(args.length() == 3);
2807
2808 CONVERT_CHECKED(String, value, args[0]);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002809 Object* from = args[1];
2810 Object* to = args[2];
2811 int start, end;
2812 // We have a fast integer-only case here to avoid a conversion to double in
2813 // the common case where from and to are Smis.
2814 if (from->IsSmi() && to->IsSmi()) {
2815 start = Smi::cast(from)->value();
2816 end = Smi::cast(to)->value();
2817 } else {
2818 CONVERT_DOUBLE_CHECKED(from_number, from);
2819 CONVERT_DOUBLE_CHECKED(to_number, to);
2820 start = FastD2I(from_number);
2821 end = FastD2I(to_number);
2822 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002823 RUNTIME_ASSERT(end >= start);
2824 RUNTIME_ASSERT(start >= 0);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00002825 RUNTIME_ASSERT(end <= value->length());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002826 Counters::sub_string_runtime.Increment();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002827 return value->SubString(start, end);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002828}
2829
2830
lrn@chromium.org303ada72010-10-27 09:33:13 +00002831static MaybeObject* Runtime_StringMatch(Arguments args) {
ager@chromium.org41826e72009-03-30 13:30:57 +00002832 ASSERT_EQ(3, args.length());
2833
2834 CONVERT_ARG_CHECKED(String, subject, 0);
2835 CONVERT_ARG_CHECKED(JSRegExp, regexp, 1);
2836 CONVERT_ARG_CHECKED(JSArray, regexp_info, 2);
2837 HandleScope handles;
2838
2839 Handle<Object> match = RegExpImpl::Exec(regexp, subject, 0, regexp_info);
2840
2841 if (match.is_null()) {
2842 return Failure::Exception();
2843 }
2844 if (match->IsNull()) {
2845 return Heap::null_value();
2846 }
2847 int length = subject->length();
2848
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00002849 CompilationZoneScope zone_space(DELETE_ON_EXIT);
ager@chromium.org41826e72009-03-30 13:30:57 +00002850 ZoneList<int> offsets(8);
2851 do {
2852 int start;
2853 int end;
2854 {
2855 AssertNoAllocation no_alloc;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002856 FixedArray* elements = FixedArray::cast(regexp_info->elements());
ager@chromium.org41826e72009-03-30 13:30:57 +00002857 start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value();
2858 end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value();
2859 }
2860 offsets.Add(start);
2861 offsets.Add(end);
2862 int index = start < end ? end : end + 1;
2863 if (index > length) break;
2864 match = RegExpImpl::Exec(regexp, subject, index, regexp_info);
2865 if (match.is_null()) {
2866 return Failure::Exception();
2867 }
2868 } while (!match->IsNull());
2869 int matches = offsets.length() / 2;
2870 Handle<FixedArray> elements = Factory::NewFixedArray(matches);
2871 for (int i = 0; i < matches ; i++) {
2872 int from = offsets.at(i * 2);
2873 int to = offsets.at(i * 2 + 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002874 Handle<String> match = Factory::NewSubString(subject, from, to);
2875 elements->set(i, *match);
ager@chromium.org41826e72009-03-30 13:30:57 +00002876 }
2877 Handle<JSArray> result = Factory::NewJSArrayWithElements(elements);
2878 result->set_length(Smi::FromInt(matches));
2879 return *result;
2880}
2881
2882
lrn@chromium.org25156de2010-04-06 13:10:27 +00002883// Two smis before and after the match, for very long strings.
2884const int kMaxBuilderEntriesPerRegExpMatch = 5;
2885
2886
2887static void SetLastMatchInfoNoCaptures(Handle<String> subject,
2888 Handle<JSArray> last_match_info,
2889 int match_start,
2890 int match_end) {
2891 // Fill last_match_info with a single capture.
2892 last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead);
2893 AssertNoAllocation no_gc;
2894 FixedArray* elements = FixedArray::cast(last_match_info->elements());
2895 RegExpImpl::SetLastCaptureCount(elements, 2);
2896 RegExpImpl::SetLastInput(elements, *subject);
2897 RegExpImpl::SetLastSubject(elements, *subject);
2898 RegExpImpl::SetCapture(elements, 0, match_start);
2899 RegExpImpl::SetCapture(elements, 1, match_end);
2900}
2901
2902
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002903template <typename SubjectChar, typename PatternChar>
2904static bool SearchStringMultiple(Vector<const SubjectChar> subject,
2905 Vector<const PatternChar> pattern,
2906 String* pattern_string,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002907 FixedArrayBuilder* builder,
2908 int* match_pos) {
2909 int pos = *match_pos;
2910 int subject_length = subject.length();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002911 int pattern_length = pattern.length();
lrn@chromium.org25156de2010-04-06 13:10:27 +00002912 int max_search_start = subject_length - pattern_length;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002913 StringSearch<PatternChar, SubjectChar> search(pattern);
2914 while (pos <= max_search_start) {
2915 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
2916 *match_pos = pos;
2917 return false;
2918 }
2919 // Position of end of previous match.
2920 int match_end = pos + pattern_length;
2921 int new_pos = search.Search(subject, match_end);
2922 if (new_pos >= 0) {
2923 // A match.
2924 if (new_pos > match_end) {
2925 ReplacementStringBuilder::AddSubjectSlice(builder,
2926 match_end,
2927 new_pos);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002928 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002929 pos = new_pos;
2930 builder->Add(pattern_string);
2931 } else {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002932 break;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002933 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00002934 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002935
lrn@chromium.org25156de2010-04-06 13:10:27 +00002936 if (pos < max_search_start) {
2937 ReplacementStringBuilder::AddSubjectSlice(builder,
2938 pos + pattern_length,
2939 subject_length);
2940 }
2941 *match_pos = pos;
2942 return true;
2943}
2944
2945
2946static bool SearchStringMultiple(Handle<String> subject,
2947 Handle<String> pattern,
2948 Handle<JSArray> last_match_info,
2949 FixedArrayBuilder* builder) {
2950 ASSERT(subject->IsFlat());
2951 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002952
2953 // Treating as if a previous match was before first character.
2954 int match_pos = -pattern->length();
2955
2956 for (;;) { // Break when search complete.
2957 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
2958 AssertNoAllocation no_gc;
2959 if (subject->IsAsciiRepresentation()) {
2960 Vector<const char> subject_vector = subject->ToAsciiVector();
2961 if (pattern->IsAsciiRepresentation()) {
2962 if (SearchStringMultiple(subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002963 pattern->ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002964 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002965 builder,
2966 &match_pos)) break;
2967 } else {
2968 if (SearchStringMultiple(subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002969 pattern->ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002970 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002971 builder,
2972 &match_pos)) break;
2973 }
2974 } else {
2975 Vector<const uc16> subject_vector = subject->ToUC16Vector();
2976 if (pattern->IsAsciiRepresentation()) {
2977 if (SearchStringMultiple(subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002978 pattern->ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002979 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002980 builder,
2981 &match_pos)) break;
2982 } else {
2983 if (SearchStringMultiple(subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002984 pattern->ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002985 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002986 builder,
2987 &match_pos)) break;
2988 }
2989 }
2990 }
2991
2992 if (match_pos >= 0) {
2993 SetLastMatchInfoNoCaptures(subject,
2994 last_match_info,
2995 match_pos,
2996 match_pos + pattern->length());
2997 return true;
2998 }
2999 return false; // No matches at all.
3000}
3001
3002
3003static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple(
3004 Handle<String> subject,
3005 Handle<JSRegExp> regexp,
3006 Handle<JSArray> last_match_array,
3007 FixedArrayBuilder* builder) {
3008 ASSERT(subject->IsFlat());
3009 int match_start = -1;
3010 int match_end = 0;
3011 int pos = 0;
3012 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3013 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3014
3015 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003016 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003017 int subject_length = subject->length();
3018
3019 for (;;) { // Break on failure, return on exception.
3020 RegExpImpl::IrregexpResult result =
3021 RegExpImpl::IrregexpExecOnce(regexp,
3022 subject,
3023 pos,
3024 register_vector);
3025 if (result == RegExpImpl::RE_SUCCESS) {
3026 match_start = register_vector[0];
3027 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3028 if (match_end < match_start) {
3029 ReplacementStringBuilder::AddSubjectSlice(builder,
3030 match_end,
3031 match_start);
3032 }
3033 match_end = register_vector[1];
3034 HandleScope loop_scope;
3035 builder->Add(*Factory::NewSubString(subject, match_start, match_end));
3036 if (match_start != match_end) {
3037 pos = match_end;
3038 } else {
3039 pos = match_end + 1;
3040 if (pos > subject_length) break;
3041 }
3042 } else if (result == RegExpImpl::RE_FAILURE) {
3043 break;
3044 } else {
3045 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3046 return result;
3047 }
3048 }
3049
3050 if (match_start >= 0) {
3051 if (match_end < subject_length) {
3052 ReplacementStringBuilder::AddSubjectSlice(builder,
3053 match_end,
3054 subject_length);
3055 }
3056 SetLastMatchInfoNoCaptures(subject,
3057 last_match_array,
3058 match_start,
3059 match_end);
3060 return RegExpImpl::RE_SUCCESS;
3061 } else {
3062 return RegExpImpl::RE_FAILURE; // No matches at all.
3063 }
3064}
3065
3066
3067static RegExpImpl::IrregexpResult SearchRegExpMultiple(
3068 Handle<String> subject,
3069 Handle<JSRegExp> regexp,
3070 Handle<JSArray> last_match_array,
3071 FixedArrayBuilder* builder) {
3072
3073 ASSERT(subject->IsFlat());
3074 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3075 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3076
3077 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003078 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003079
3080 RegExpImpl::IrregexpResult result =
3081 RegExpImpl::IrregexpExecOnce(regexp,
3082 subject,
3083 0,
3084 register_vector);
3085
3086 int capture_count = regexp->CaptureCount();
3087 int subject_length = subject->length();
3088
3089 // Position to search from.
3090 int pos = 0;
3091 // End of previous match. Differs from pos if match was empty.
3092 int match_end = 0;
3093 if (result == RegExpImpl::RE_SUCCESS) {
3094 // Need to keep a copy of the previous match for creating last_match_info
3095 // at the end, so we have two vectors that we swap between.
3096 OffsetsVector registers2(required_registers);
3097 Vector<int> prev_register_vector(registers2.vector(), registers2.length());
3098
3099 do {
3100 int match_start = register_vector[0];
3101 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3102 if (match_end < match_start) {
3103 ReplacementStringBuilder::AddSubjectSlice(builder,
3104 match_end,
3105 match_start);
3106 }
3107 match_end = register_vector[1];
3108
3109 {
3110 // Avoid accumulating new handles inside loop.
3111 HandleScope temp_scope;
3112 // Arguments array to replace function is match, captures, index and
3113 // subject, i.e., 3 + capture count in total.
3114 Handle<FixedArray> elements = Factory::NewFixedArray(3 + capture_count);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003115 Handle<String> match = Factory::NewSubString(subject,
3116 match_start,
3117 match_end);
3118 elements->set(0, *match);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003119 for (int i = 1; i <= capture_count; i++) {
3120 int start = register_vector[i * 2];
3121 if (start >= 0) {
3122 int end = register_vector[i * 2 + 1];
3123 ASSERT(start <= end);
3124 Handle<String> substring = Factory::NewSubString(subject,
3125 start,
3126 end);
3127 elements->set(i, *substring);
3128 } else {
3129 ASSERT(register_vector[i * 2 + 1] < 0);
3130 elements->set(i, Heap::undefined_value());
3131 }
3132 }
3133 elements->set(capture_count + 1, Smi::FromInt(match_start));
3134 elements->set(capture_count + 2, *subject);
3135 builder->Add(*Factory::NewJSArrayWithElements(elements));
3136 }
3137 // Swap register vectors, so the last successful match is in
3138 // prev_register_vector.
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003139 Vector<int32_t> tmp = prev_register_vector;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003140 prev_register_vector = register_vector;
3141 register_vector = tmp;
3142
3143 if (match_end > match_start) {
3144 pos = match_end;
3145 } else {
3146 pos = match_end + 1;
3147 if (pos > subject_length) {
3148 break;
3149 }
3150 }
3151
3152 result = RegExpImpl::IrregexpExecOnce(regexp,
3153 subject,
3154 pos,
3155 register_vector);
3156 } while (result == RegExpImpl::RE_SUCCESS);
3157
3158 if (result != RegExpImpl::RE_EXCEPTION) {
3159 // Finished matching, with at least one match.
3160 if (match_end < subject_length) {
3161 ReplacementStringBuilder::AddSubjectSlice(builder,
3162 match_end,
3163 subject_length);
3164 }
3165
3166 int last_match_capture_count = (capture_count + 1) * 2;
3167 int last_match_array_size =
3168 last_match_capture_count + RegExpImpl::kLastMatchOverhead;
3169 last_match_array->EnsureSize(last_match_array_size);
3170 AssertNoAllocation no_gc;
3171 FixedArray* elements = FixedArray::cast(last_match_array->elements());
3172 RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count);
3173 RegExpImpl::SetLastSubject(elements, *subject);
3174 RegExpImpl::SetLastInput(elements, *subject);
3175 for (int i = 0; i < last_match_capture_count; i++) {
3176 RegExpImpl::SetCapture(elements, i, prev_register_vector[i]);
3177 }
3178 return RegExpImpl::RE_SUCCESS;
3179 }
3180 }
3181 // No matches at all, return failure or exception result directly.
3182 return result;
3183}
3184
3185
lrn@chromium.org303ada72010-10-27 09:33:13 +00003186static MaybeObject* Runtime_RegExpExecMultiple(Arguments args) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003187 ASSERT(args.length() == 4);
3188 HandleScope handles;
3189
3190 CONVERT_ARG_CHECKED(String, subject, 1);
3191 if (!subject->IsFlat()) { FlattenString(subject); }
3192 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
3193 CONVERT_ARG_CHECKED(JSArray, last_match_info, 2);
3194 CONVERT_ARG_CHECKED(JSArray, result_array, 3);
3195
3196 ASSERT(last_match_info->HasFastElements());
3197 ASSERT(regexp->GetFlags().is_global());
3198 Handle<FixedArray> result_elements;
3199 if (result_array->HasFastElements()) {
3200 result_elements =
3201 Handle<FixedArray>(FixedArray::cast(result_array->elements()));
3202 } else {
3203 result_elements = Factory::NewFixedArrayWithHoles(16);
3204 }
3205 FixedArrayBuilder builder(result_elements);
3206
3207 if (regexp->TypeTag() == JSRegExp::ATOM) {
3208 Handle<String> pattern(
3209 String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003210 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003211 if (SearchStringMultiple(subject, pattern, last_match_info, &builder)) {
3212 return *builder.ToJSArray(result_array);
3213 }
3214 return Heap::null_value();
3215 }
3216
3217 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
3218
3219 RegExpImpl::IrregexpResult result;
3220 if (regexp->CaptureCount() == 0) {
3221 result = SearchRegExpNoCaptureMultiple(subject,
3222 regexp,
3223 last_match_info,
3224 &builder);
3225 } else {
3226 result = SearchRegExpMultiple(subject, regexp, last_match_info, &builder);
3227 }
3228 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array);
3229 if (result == RegExpImpl::RE_FAILURE) return Heap::null_value();
3230 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3231 return Failure::Exception();
3232}
3233
3234
lrn@chromium.org303ada72010-10-27 09:33:13 +00003235static MaybeObject* Runtime_NumberToRadixString(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003236 NoHandleAllocation ha;
3237 ASSERT(args.length() == 2);
3238
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003239 // Fast case where the result is a one character string.
3240 if (args[0]->IsSmi() && args[1]->IsSmi()) {
3241 int value = Smi::cast(args[0])->value();
3242 int radix = Smi::cast(args[1])->value();
3243 if (value >= 0 && value < radix) {
3244 RUNTIME_ASSERT(radix <= 36);
3245 // Character array used for conversion.
3246 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
3247 return Heap::LookupSingleCharacterStringFromCode(kCharTable[value]);
3248 }
3249 }
3250
3251 // Slow case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003252 CONVERT_DOUBLE_CHECKED(value, args[0]);
3253 if (isnan(value)) {
3254 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
3255 }
3256 if (isinf(value)) {
3257 if (value < 0) {
3258 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
3259 }
3260 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
3261 }
3262 CONVERT_DOUBLE_CHECKED(radix_number, args[1]);
3263 int radix = FastD2I(radix_number);
3264 RUNTIME_ASSERT(2 <= radix && radix <= 36);
3265 char* str = DoubleToRadixCString(value, radix);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003266 MaybeObject* result = Heap::AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003267 DeleteArray(str);
3268 return result;
3269}
3270
3271
lrn@chromium.org303ada72010-10-27 09:33:13 +00003272static MaybeObject* Runtime_NumberToFixed(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003273 NoHandleAllocation ha;
3274 ASSERT(args.length() == 2);
3275
3276 CONVERT_DOUBLE_CHECKED(value, args[0]);
3277 if (isnan(value)) {
3278 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
3279 }
3280 if (isinf(value)) {
3281 if (value < 0) {
3282 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
3283 }
3284 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
3285 }
3286 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3287 int f = FastD2I(f_number);
3288 RUNTIME_ASSERT(f >= 0);
3289 char* str = DoubleToFixedCString(value, f);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003290 MaybeObject* result = Heap::AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003291 DeleteArray(str);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003292 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003293}
3294
3295
lrn@chromium.org303ada72010-10-27 09:33:13 +00003296static MaybeObject* Runtime_NumberToExponential(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003297 NoHandleAllocation ha;
3298 ASSERT(args.length() == 2);
3299
3300 CONVERT_DOUBLE_CHECKED(value, args[0]);
3301 if (isnan(value)) {
3302 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
3303 }
3304 if (isinf(value)) {
3305 if (value < 0) {
3306 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
3307 }
3308 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
3309 }
3310 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3311 int f = FastD2I(f_number);
3312 RUNTIME_ASSERT(f >= -1 && f <= 20);
3313 char* str = DoubleToExponentialCString(value, f);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003314 MaybeObject* result = Heap::AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003315 DeleteArray(str);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003316 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003317}
3318
3319
lrn@chromium.org303ada72010-10-27 09:33:13 +00003320static MaybeObject* Runtime_NumberToPrecision(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003321 NoHandleAllocation ha;
3322 ASSERT(args.length() == 2);
3323
3324 CONVERT_DOUBLE_CHECKED(value, args[0]);
3325 if (isnan(value)) {
3326 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
3327 }
3328 if (isinf(value)) {
3329 if (value < 0) {
3330 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
3331 }
3332 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
3333 }
3334 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3335 int f = FastD2I(f_number);
3336 RUNTIME_ASSERT(f >= 1 && f <= 21);
3337 char* str = DoubleToPrecisionCString(value, f);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003338 MaybeObject* result = Heap::AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003339 DeleteArray(str);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003340 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003341}
3342
3343
3344// Returns a single character string where first character equals
3345// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003346static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003347 if (index < static_cast<uint32_t>(string->length())) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003348 string->TryFlatten();
ager@chromium.org870a0b62008-11-04 11:43:05 +00003349 return LookupSingleCharacterStringFromCode(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003350 string->Get(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003351 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003352 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003353}
3354
3355
lrn@chromium.org303ada72010-10-27 09:33:13 +00003356MaybeObject* Runtime::GetElementOrCharAt(Handle<Object> object,
3357 uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003358 // Handle [] indexing on Strings
3359 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003360 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
3361 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003362 }
3363
3364 // Handle [] indexing on String objects
3365 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003366 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
3367 Handle<Object> result =
3368 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
3369 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003370 }
3371
3372 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003373 Handle<Object> prototype = GetPrototype(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003374 return prototype->GetElement(index);
3375 }
3376
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003377 return GetElement(object, index);
3378}
3379
3380
lrn@chromium.org303ada72010-10-27 09:33:13 +00003381MaybeObject* Runtime::GetElement(Handle<Object> object, uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003382 return object->GetElement(index);
3383}
3384
3385
lrn@chromium.org303ada72010-10-27 09:33:13 +00003386MaybeObject* Runtime::GetObjectProperty(Handle<Object> object,
3387 Handle<Object> key) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003388 HandleScope scope;
3389
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003390 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003391 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003392 Handle<Object> error =
3393 Factory::NewTypeError("non_object_property_load",
3394 HandleVector(args, 2));
3395 return Top::Throw(*error);
3396 }
3397
3398 // Check if the given key is an array index.
3399 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003400 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003401 return GetElementOrCharAt(object, index);
3402 }
3403
3404 // Convert the key to a string - possibly by calling back into JavaScript.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003405 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003406 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003407 name = Handle<String>::cast(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003408 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003409 bool has_pending_exception = false;
3410 Handle<Object> converted =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003411 Execution::ToString(key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003412 if (has_pending_exception) return Failure::Exception();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003413 name = Handle<String>::cast(converted);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003414 }
3415
ager@chromium.org32912102009-01-16 10:38:43 +00003416 // Check if the name is trivially convertible to an index and get
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003417 // the element if so.
3418 if (name->AsArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003419 return GetElementOrCharAt(object, index);
3420 } else {
3421 PropertyAttributes attr;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003422 return object->GetProperty(*name, &attr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003423 }
3424}
3425
3426
lrn@chromium.org303ada72010-10-27 09:33:13 +00003427static MaybeObject* Runtime_GetProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003428 NoHandleAllocation ha;
3429 ASSERT(args.length() == 2);
3430
3431 Handle<Object> object = args.at<Object>(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003432 Handle<Object> key = args.at<Object>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003433
3434 return Runtime::GetObjectProperty(object, key);
3435}
3436
3437
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003438// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003439static MaybeObject* Runtime_KeyedGetProperty(Arguments args) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00003440 NoHandleAllocation ha;
3441 ASSERT(args.length() == 2);
3442
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003443 // Fast cases for getting named properties of the receiver JSObject
ager@chromium.org8bb60582008-12-11 12:02:20 +00003444 // itself.
3445 //
3446 // The global proxy objects has to be excluded since LocalLookup on
ager@chromium.org32912102009-01-16 10:38:43 +00003447 // the global proxy object can return a valid result even though the
ager@chromium.org8bb60582008-12-11 12:02:20 +00003448 // global proxy object never has properties. This is the case
3449 // because the global proxy object forwards everything to its hidden
3450 // prototype including local lookups.
3451 //
3452 // Additionally, we need to make sure that we do not cache results
3453 // for objects that require access checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003454 if (args[0]->IsJSObject() &&
3455 !args[0]->IsJSGlobalProxy() &&
ager@chromium.org8bb60582008-12-11 12:02:20 +00003456 !args[0]->IsAccessCheckNeeded() &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003457 args[1]->IsString()) {
3458 JSObject* receiver = JSObject::cast(args[0]);
3459 String* key = String::cast(args[1]);
3460 if (receiver->HasFastProperties()) {
3461 // Attempt to use lookup cache.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003462 Map* receiver_map = receiver->map();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00003463 int offset = KeyedLookupCache::Lookup(receiver_map, key);
3464 if (offset != -1) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003465 Object* value = receiver->FastPropertyAt(offset);
3466 return value->IsTheHole() ? Heap::undefined_value() : value;
3467 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003468 // Lookup cache miss. Perform lookup and update the cache if appropriate.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003469 LookupResult result;
3470 receiver->LocalLookup(key, &result);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00003471 if (result.IsProperty() && result.type() == FIELD) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003472 int offset = result.GetFieldIndex();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00003473 KeyedLookupCache::Update(receiver_map, key, offset);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003474 return receiver->FastPropertyAt(offset);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003475 }
3476 } else {
3477 // Attempt dictionary lookup.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00003478 StringDictionary* dictionary = receiver->property_dictionary();
3479 int entry = dictionary->FindEntry(key);
3480 if ((entry != StringDictionary::kNotFound) &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003481 (dictionary->DetailsAt(entry).type() == NORMAL)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003482 Object* value = dictionary->ValueAt(entry);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003483 if (!receiver->IsGlobalObject()) return value;
3484 value = JSGlobalPropertyCell::cast(value)->value();
3485 if (!value->IsTheHole()) return value;
3486 // If value is the hole do the general lookup.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003487 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00003488 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003489 } else if (args[0]->IsString() && args[1]->IsSmi()) {
3490 // Fast case for string indexing using [] with a smi index.
3491 HandleScope scope;
3492 Handle<String> str = args.at<String>(0);
3493 int index = Smi::cast(args[1])->value();
3494 Handle<Object> result = GetCharAt(str, index);
3495 return *result;
ager@chromium.org7c537e22008-10-16 08:43:32 +00003496 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003497
3498 // Fall back to GetObjectProperty.
ager@chromium.org7c537e22008-10-16 08:43:32 +00003499 return Runtime::GetObjectProperty(args.at<Object>(0),
3500 args.at<Object>(1));
3501}
3502
3503
lrn@chromium.org303ada72010-10-27 09:33:13 +00003504static MaybeObject* Runtime_DefineOrRedefineAccessorProperty(Arguments args) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003505 ASSERT(args.length() == 5);
3506 HandleScope scope;
3507 CONVERT_ARG_CHECKED(JSObject, obj, 0);
3508 CONVERT_CHECKED(String, name, args[1]);
3509 CONVERT_CHECKED(Smi, flag_setter, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003510 Object* fun = args[3];
3511 RUNTIME_ASSERT(fun->IsJSFunction() || fun->IsUndefined());
ager@chromium.org5c838252010-02-19 08:53:10 +00003512 CONVERT_CHECKED(Smi, flag_attr, args[4]);
3513 int unchecked = flag_attr->value();
3514 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3515 RUNTIME_ASSERT(!obj->IsNull());
3516 LookupResult result;
3517 obj->LocalLookupRealNamedProperty(name, &result);
3518
3519 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
3520 // If an existing property is either FIELD, NORMAL or CONSTANT_FUNCTION
3521 // delete it to avoid running into trouble in DefineAccessor, which
3522 // handles this incorrectly if the property is readonly (does nothing)
3523 if (result.IsProperty() &&
3524 (result.type() == FIELD || result.type() == NORMAL
3525 || result.type() == CONSTANT_FUNCTION)) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003526 Object* ok;
3527 { MaybeObject* maybe_ok =
3528 obj->DeleteProperty(name, JSObject::NORMAL_DELETION);
3529 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
3530 }
ager@chromium.org5c838252010-02-19 08:53:10 +00003531 }
3532 return obj->DefineAccessor(name, flag_setter->value() == 0, fun, attr);
3533}
3534
lrn@chromium.org303ada72010-10-27 09:33:13 +00003535static MaybeObject* Runtime_DefineOrRedefineDataProperty(Arguments args) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003536 ASSERT(args.length() == 4);
3537 HandleScope scope;
3538 CONVERT_ARG_CHECKED(JSObject, js_object, 0);
3539 CONVERT_ARG_CHECKED(String, name, 1);
3540 Handle<Object> obj_value = args.at<Object>(2);
3541
3542 CONVERT_CHECKED(Smi, flag, args[3]);
3543 int unchecked = flag->value();
3544 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3545
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003546 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
3547
3548 // Check if this is an element.
3549 uint32_t index;
3550 bool is_element = name->AsArrayIndex(&index);
3551
3552 // Special case for elements if any of the flags are true.
3553 // If elements are in fast case we always implicitly assume that:
3554 // DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
3555 if (((unchecked & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0) &&
3556 is_element) {
3557 // Normalize the elements to enable attributes on the property.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003558 NormalizeElements(js_object);
3559 Handle<NumberDictionary> dictionary(js_object->element_dictionary());
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003560 // Make sure that we never go back to fast case.
3561 dictionary->set_requires_slow_elements();
3562 PropertyDetails details = PropertyDetails(attr, NORMAL);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003563 NumberDictionarySet(dictionary, index, obj_value, details);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003564 }
3565
ager@chromium.org5c838252010-02-19 08:53:10 +00003566 LookupResult result;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003567 js_object->LookupRealNamedProperty(*name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00003568
ager@chromium.org5c838252010-02-19 08:53:10 +00003569 // Take special care when attributes are different and there is already
3570 // a property. For simplicity we normalize the property which enables us
3571 // to not worry about changing the instance_descriptor and creating a new
3572 // map. The current version of SetObjectProperty does not handle attributes
3573 // correctly in the case where a property is a field and is reset with
3574 // new attributes.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003575 if (result.IsProperty() &&
3576 (attr != result.GetAttributes() || result.type() == CALLBACKS)) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003577 // New attributes - normalize to avoid writing to instance descriptor
lrn@chromium.org303ada72010-10-27 09:33:13 +00003578 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00003579 // Use IgnoreAttributes version since a readonly property may be
3580 // overridden and SetProperty does not allow this.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003581 return js_object->SetLocalPropertyIgnoreAttributes(*name,
3582 *obj_value,
3583 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00003584 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003585
ager@chromium.org5c838252010-02-19 08:53:10 +00003586 return Runtime::SetObjectProperty(js_object, name, obj_value, attr);
3587}
3588
3589
lrn@chromium.org303ada72010-10-27 09:33:13 +00003590MaybeObject* Runtime::SetObjectProperty(Handle<Object> object,
3591 Handle<Object> key,
3592 Handle<Object> value,
3593 PropertyAttributes attr) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003594 HandleScope scope;
3595
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003596 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003597 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003598 Handle<Object> error =
3599 Factory::NewTypeError("non_object_property_store",
3600 HandleVector(args, 2));
3601 return Top::Throw(*error);
3602 }
3603
3604 // If the object isn't a JavaScript object, we ignore the store.
3605 if (!object->IsJSObject()) return *value;
3606
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003607 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
3608
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003609 // Check if the given key is an array index.
3610 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003611 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003612 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
3613 // of a string using [] notation. We need to support this too in
3614 // JavaScript.
3615 // In the case of a String object we just need to redirect the assignment to
3616 // the underlying string if the index is in range. Since the underlying
3617 // string does nothing with the assignment then we can ignore such
3618 // assignments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003619 if (js_object->IsStringObjectWithCharacterAt(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003620 return *value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003621 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003622
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003623 Handle<Object> result = SetElement(js_object, index, value);
3624 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003625 return *value;
3626 }
3627
3628 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003629 Handle<Object> result;
3630 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003631 result = SetElement(js_object, index, value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003632 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003633 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003634 key_string->TryFlatten();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003635 result = SetProperty(js_object, key_string, value, attr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003636 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003637 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003638 return *value;
3639 }
3640
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003641 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003642 bool has_pending_exception = false;
3643 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
3644 if (has_pending_exception) return Failure::Exception();
3645 Handle<String> name = Handle<String>::cast(converted);
3646
3647 if (name->AsArrayIndex(&index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003648 return js_object->SetElement(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003649 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003650 return js_object->SetProperty(*name, *value, attr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003651 }
3652}
3653
3654
lrn@chromium.org303ada72010-10-27 09:33:13 +00003655MaybeObject* Runtime::ForceSetObjectProperty(Handle<JSObject> js_object,
3656 Handle<Object> key,
3657 Handle<Object> value,
3658 PropertyAttributes attr) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003659 HandleScope scope;
3660
3661 // Check if the given key is an array index.
3662 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003663 if (key->ToArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003664 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
3665 // of a string using [] notation. We need to support this too in
3666 // JavaScript.
3667 // In the case of a String object we just need to redirect the assignment to
3668 // the underlying string if the index is in range. Since the underlying
3669 // string does nothing with the assignment then we can ignore such
3670 // assignments.
3671 if (js_object->IsStringObjectWithCharacterAt(index)) {
3672 return *value;
3673 }
3674
3675 return js_object->SetElement(index, *value);
3676 }
3677
3678 if (key->IsString()) {
3679 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003680 return js_object->SetElement(index, *value);
3681 } else {
3682 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003683 key_string->TryFlatten();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003684 return js_object->SetLocalPropertyIgnoreAttributes(*key_string,
3685 *value,
3686 attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003687 }
3688 }
3689
3690 // Call-back into JavaScript to convert the key to a string.
3691 bool has_pending_exception = false;
3692 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
3693 if (has_pending_exception) return Failure::Exception();
3694 Handle<String> name = Handle<String>::cast(converted);
3695
3696 if (name->AsArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003697 return js_object->SetElement(index, *value);
3698 } else {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003699 return js_object->SetLocalPropertyIgnoreAttributes(*name, *value, attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003700 }
3701}
3702
3703
lrn@chromium.org303ada72010-10-27 09:33:13 +00003704MaybeObject* Runtime::ForceDeleteObjectProperty(Handle<JSObject> js_object,
3705 Handle<Object> key) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00003706 HandleScope scope;
3707
3708 // Check if the given key is an array index.
3709 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003710 if (key->ToArrayIndex(&index)) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00003711 // In Firefox/SpiderMonkey, Safari and Opera you can access the
3712 // characters of a string using [] notation. In the case of a
3713 // String object we just need to redirect the deletion to the
3714 // underlying string if the index is in range. Since the
3715 // underlying string does nothing with the deletion, we can ignore
3716 // such deletions.
3717 if (js_object->IsStringObjectWithCharacterAt(index)) {
3718 return Heap::true_value();
3719 }
3720
3721 return js_object->DeleteElement(index, JSObject::FORCE_DELETION);
3722 }
3723
3724 Handle<String> key_string;
3725 if (key->IsString()) {
3726 key_string = Handle<String>::cast(key);
3727 } else {
3728 // Call-back into JavaScript to convert the key to a string.
3729 bool has_pending_exception = false;
3730 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
3731 if (has_pending_exception) return Failure::Exception();
3732 key_string = Handle<String>::cast(converted);
3733 }
3734
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003735 key_string->TryFlatten();
ager@chromium.orge2902be2009-06-08 12:21:35 +00003736 return js_object->DeleteProperty(*key_string, JSObject::FORCE_DELETION);
3737}
3738
3739
lrn@chromium.org303ada72010-10-27 09:33:13 +00003740static MaybeObject* Runtime_SetProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003741 NoHandleAllocation ha;
3742 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
3743
3744 Handle<Object> object = args.at<Object>(0);
3745 Handle<Object> key = args.at<Object>(1);
3746 Handle<Object> value = args.at<Object>(2);
3747
3748 // Compute attributes.
3749 PropertyAttributes attributes = NONE;
3750 if (args.length() == 4) {
3751 CONVERT_CHECKED(Smi, value_obj, args[3]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003752 int unchecked_value = value_obj->value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003753 // Only attribute bits should be set.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003754 RUNTIME_ASSERT(
3755 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3756 attributes = static_cast<PropertyAttributes>(unchecked_value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003757 }
3758 return Runtime::SetObjectProperty(object, key, value, attributes);
3759}
3760
3761
3762// Set a local property, even if it is READ_ONLY. If the property does not
3763// exist, it will be added with attributes NONE.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003764static MaybeObject* Runtime_IgnoreAttributesAndSetProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003765 NoHandleAllocation ha;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003766 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003767 CONVERT_CHECKED(JSObject, object, args[0]);
3768 CONVERT_CHECKED(String, name, args[1]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003769 // Compute attributes.
3770 PropertyAttributes attributes = NONE;
3771 if (args.length() == 4) {
3772 CONVERT_CHECKED(Smi, value_obj, args[3]);
3773 int unchecked_value = value_obj->value();
3774 // Only attribute bits should be set.
3775 RUNTIME_ASSERT(
3776 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3777 attributes = static_cast<PropertyAttributes>(unchecked_value);
3778 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003779
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003780 return object->
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003781 SetLocalPropertyIgnoreAttributes(name, args[2], attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003782}
3783
3784
lrn@chromium.org303ada72010-10-27 09:33:13 +00003785static MaybeObject* Runtime_DeleteProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003786 NoHandleAllocation ha;
3787 ASSERT(args.length() == 2);
3788
3789 CONVERT_CHECKED(JSObject, object, args[0]);
3790 CONVERT_CHECKED(String, key, args[1]);
ager@chromium.orge2902be2009-06-08 12:21:35 +00003791 return object->DeleteProperty(key, JSObject::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003792}
3793
3794
ager@chromium.org9085a012009-05-11 19:22:57 +00003795static Object* HasLocalPropertyImplementation(Handle<JSObject> object,
3796 Handle<String> key) {
3797 if (object->HasLocalProperty(*key)) return Heap::true_value();
3798 // Handle hidden prototypes. If there's a hidden prototype above this thing
3799 // then we have to check it for properties, because they are supposed to
3800 // look like they are on this object.
3801 Handle<Object> proto(object->GetPrototype());
3802 if (proto->IsJSObject() &&
3803 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
3804 return HasLocalPropertyImplementation(Handle<JSObject>::cast(proto), key);
3805 }
3806 return Heap::false_value();
3807}
3808
3809
lrn@chromium.org303ada72010-10-27 09:33:13 +00003810static MaybeObject* Runtime_HasLocalProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003811 NoHandleAllocation ha;
3812 ASSERT(args.length() == 2);
3813 CONVERT_CHECKED(String, key, args[1]);
3814
ager@chromium.org9085a012009-05-11 19:22:57 +00003815 Object* obj = args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003816 // Only JS objects can have properties.
ager@chromium.org9085a012009-05-11 19:22:57 +00003817 if (obj->IsJSObject()) {
3818 JSObject* object = JSObject::cast(obj);
3819 // Fast case - no interceptors.
3820 if (object->HasRealNamedProperty(key)) return Heap::true_value();
3821 // Slow case. Either it's not there or we have an interceptor. We should
3822 // have handles for this kind of deal.
3823 HandleScope scope;
3824 return HasLocalPropertyImplementation(Handle<JSObject>(object),
3825 Handle<String>(key));
3826 } else if (obj->IsString()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003827 // Well, there is one exception: Handle [] on strings.
3828 uint32_t index;
3829 if (key->AsArrayIndex(&index)) {
ager@chromium.org9085a012009-05-11 19:22:57 +00003830 String* string = String::cast(obj);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003831 if (index < static_cast<uint32_t>(string->length()))
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003832 return Heap::true_value();
3833 }
3834 }
3835 return Heap::false_value();
3836}
3837
3838
lrn@chromium.org303ada72010-10-27 09:33:13 +00003839static MaybeObject* Runtime_HasProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003840 NoHandleAllocation na;
3841 ASSERT(args.length() == 2);
3842
3843 // Only JS objects can have properties.
3844 if (args[0]->IsJSObject()) {
3845 JSObject* object = JSObject::cast(args[0]);
3846 CONVERT_CHECKED(String, key, args[1]);
3847 if (object->HasProperty(key)) return Heap::true_value();
3848 }
3849 return Heap::false_value();
3850}
3851
3852
lrn@chromium.org303ada72010-10-27 09:33:13 +00003853static MaybeObject* Runtime_HasElement(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003854 NoHandleAllocation na;
3855 ASSERT(args.length() == 2);
3856
3857 // Only JS objects can have elements.
3858 if (args[0]->IsJSObject()) {
3859 JSObject* object = JSObject::cast(args[0]);
3860 CONVERT_CHECKED(Smi, index_obj, args[1]);
3861 uint32_t index = index_obj->value();
3862 if (object->HasElement(index)) return Heap::true_value();
3863 }
3864 return Heap::false_value();
3865}
3866
3867
lrn@chromium.org303ada72010-10-27 09:33:13 +00003868static MaybeObject* Runtime_IsPropertyEnumerable(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003869 NoHandleAllocation ha;
3870 ASSERT(args.length() == 2);
3871
3872 CONVERT_CHECKED(JSObject, object, args[0]);
3873 CONVERT_CHECKED(String, key, args[1]);
3874
3875 uint32_t index;
3876 if (key->AsArrayIndex(&index)) {
3877 return Heap::ToBoolean(object->HasElement(index));
3878 }
3879
ager@chromium.org870a0b62008-11-04 11:43:05 +00003880 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
3881 return Heap::ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003882}
3883
3884
lrn@chromium.org303ada72010-10-27 09:33:13 +00003885static MaybeObject* Runtime_GetPropertyNames(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003886 HandleScope scope;
3887 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00003888 CONVERT_ARG_CHECKED(JSObject, object, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003889 return *GetKeysFor(object);
3890}
3891
3892
3893// Returns either a FixedArray as Runtime_GetPropertyNames,
3894// or, if the given object has an enum cache that contains
3895// all enumerable properties of the object and its prototypes
3896// have none, the map of the object. This is used to speed up
3897// the check for deletions during a for-in.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003898static MaybeObject* Runtime_GetPropertyNamesFast(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003899 ASSERT(args.length() == 1);
3900
3901 CONVERT_CHECKED(JSObject, raw_object, args[0]);
3902
3903 if (raw_object->IsSimpleEnum()) return raw_object->map();
3904
3905 HandleScope scope;
3906 Handle<JSObject> object(raw_object);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00003907 Handle<FixedArray> content = GetKeysInFixedArrayFor(object,
3908 INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003909
3910 // Test again, since cache may have been built by preceding call.
3911 if (object->IsSimpleEnum()) return object->map();
3912
3913 return *content;
3914}
3915
3916
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003917// Find the length of the prototype chain that is to to handled as one. If a
3918// prototype object is hidden it is to be viewed as part of the the object it
3919// is prototype for.
3920static int LocalPrototypeChainLength(JSObject* obj) {
3921 int count = 1;
3922 Object* proto = obj->GetPrototype();
3923 while (proto->IsJSObject() &&
3924 JSObject::cast(proto)->map()->is_hidden_prototype()) {
3925 count++;
3926 proto = JSObject::cast(proto)->GetPrototype();
3927 }
3928 return count;
3929}
3930
3931
3932// Return the names of the local named properties.
3933// args[0]: object
lrn@chromium.org303ada72010-10-27 09:33:13 +00003934static MaybeObject* Runtime_GetLocalPropertyNames(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003935 HandleScope scope;
3936 ASSERT(args.length() == 1);
3937 if (!args[0]->IsJSObject()) {
3938 return Heap::undefined_value();
3939 }
3940 CONVERT_ARG_CHECKED(JSObject, obj, 0);
3941
3942 // Skip the global proxy as it has no properties and always delegates to the
3943 // real global object.
3944 if (obj->IsJSGlobalProxy()) {
3945 // Only collect names if access is permitted.
3946 if (obj->IsAccessCheckNeeded() &&
3947 !Top::MayNamedAccess(*obj, Heap::undefined_value(), v8::ACCESS_KEYS)) {
3948 Top::ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
3949 return *Factory::NewJSArray(0);
3950 }
3951 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
3952 }
3953
3954 // Find the number of objects making up this.
3955 int length = LocalPrototypeChainLength(*obj);
3956
3957 // Find the number of local properties for each of the objects.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00003958 ScopedVector<int> local_property_count(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003959 int total_property_count = 0;
3960 Handle<JSObject> jsproto = obj;
3961 for (int i = 0; i < length; i++) {
3962 // Only collect names if access is permitted.
3963 if (jsproto->IsAccessCheckNeeded() &&
3964 !Top::MayNamedAccess(*jsproto,
3965 Heap::undefined_value(),
3966 v8::ACCESS_KEYS)) {
3967 Top::ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
3968 return *Factory::NewJSArray(0);
3969 }
3970 int n;
3971 n = jsproto->NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE));
3972 local_property_count[i] = n;
3973 total_property_count += n;
3974 if (i < length - 1) {
3975 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
3976 }
3977 }
3978
3979 // Allocate an array with storage for all the property names.
3980 Handle<FixedArray> names = Factory::NewFixedArray(total_property_count);
3981
3982 // Get the property names.
3983 jsproto = obj;
3984 int proto_with_hidden_properties = 0;
3985 for (int i = 0; i < length; i++) {
3986 jsproto->GetLocalPropertyNames(*names,
3987 i == 0 ? 0 : local_property_count[i - 1]);
3988 if (!GetHiddenProperties(jsproto, false)->IsUndefined()) {
3989 proto_with_hidden_properties++;
3990 }
3991 if (i < length - 1) {
3992 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
3993 }
3994 }
3995
3996 // Filter out name of hidden propeties object.
3997 if (proto_with_hidden_properties > 0) {
3998 Handle<FixedArray> old_names = names;
3999 names = Factory::NewFixedArray(
4000 names->length() - proto_with_hidden_properties);
4001 int dest_pos = 0;
4002 for (int i = 0; i < total_property_count; i++) {
4003 Object* name = old_names->get(i);
4004 if (name == Heap::hidden_symbol()) {
4005 continue;
4006 }
4007 names->set(dest_pos++, name);
4008 }
4009 }
4010
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004011 return *Factory::NewJSArrayWithElements(names);
4012}
4013
4014
4015// Return the names of the local indexed properties.
4016// args[0]: object
lrn@chromium.org303ada72010-10-27 09:33:13 +00004017static MaybeObject* Runtime_GetLocalElementNames(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004018 HandleScope scope;
4019 ASSERT(args.length() == 1);
4020 if (!args[0]->IsJSObject()) {
4021 return Heap::undefined_value();
4022 }
4023 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4024
4025 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
4026 Handle<FixedArray> names = Factory::NewFixedArray(n);
4027 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
4028 return *Factory::NewJSArrayWithElements(names);
4029}
4030
4031
4032// Return information on whether an object has a named or indexed interceptor.
4033// args[0]: object
lrn@chromium.org303ada72010-10-27 09:33:13 +00004034static MaybeObject* Runtime_GetInterceptorInfo(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004035 HandleScope scope;
4036 ASSERT(args.length() == 1);
4037 if (!args[0]->IsJSObject()) {
4038 return Smi::FromInt(0);
4039 }
4040 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4041
4042 int result = 0;
4043 if (obj->HasNamedInterceptor()) result |= 2;
4044 if (obj->HasIndexedInterceptor()) result |= 1;
4045
4046 return Smi::FromInt(result);
4047}
4048
4049
4050// Return property names from named interceptor.
4051// args[0]: object
lrn@chromium.org303ada72010-10-27 09:33:13 +00004052static MaybeObject* Runtime_GetNamedInterceptorPropertyNames(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004053 HandleScope scope;
4054 ASSERT(args.length() == 1);
4055 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4056
4057 if (obj->HasNamedInterceptor()) {
4058 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
4059 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4060 }
4061 return Heap::undefined_value();
4062}
4063
4064
4065// Return element names from indexed interceptor.
4066// args[0]: object
lrn@chromium.org303ada72010-10-27 09:33:13 +00004067static MaybeObject* Runtime_GetIndexedInterceptorElementNames(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004068 HandleScope scope;
4069 ASSERT(args.length() == 1);
4070 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4071
4072 if (obj->HasIndexedInterceptor()) {
4073 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
4074 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4075 }
4076 return Heap::undefined_value();
4077}
4078
4079
lrn@chromium.org303ada72010-10-27 09:33:13 +00004080static MaybeObject* Runtime_LocalKeys(Arguments args) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004081 ASSERT_EQ(args.length(), 1);
4082 CONVERT_CHECKED(JSObject, raw_object, args[0]);
4083 HandleScope scope;
4084 Handle<JSObject> object(raw_object);
4085 Handle<FixedArray> contents = GetKeysInFixedArrayFor(object,
4086 LOCAL_ONLY);
4087 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
4088 // property array and since the result is mutable we have to create
4089 // a fresh clone on each invocation.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004090 int length = contents->length();
4091 Handle<FixedArray> copy = Factory::NewFixedArray(length);
4092 for (int i = 0; i < length; i++) {
4093 Object* entry = contents->get(i);
4094 if (entry->IsString()) {
4095 copy->set(i, entry);
4096 } else {
4097 ASSERT(entry->IsNumber());
4098 HandleScope scope;
4099 Handle<Object> entry_handle(entry);
4100 Handle<Object> entry_str = Factory::NumberToString(entry_handle);
4101 copy->set(i, *entry_str);
4102 }
4103 }
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004104 return *Factory::NewJSArrayWithElements(copy);
4105}
4106
4107
lrn@chromium.org303ada72010-10-27 09:33:13 +00004108static MaybeObject* Runtime_GetArgumentsProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004109 NoHandleAllocation ha;
4110 ASSERT(args.length() == 1);
4111
4112 // Compute the frame holding the arguments.
4113 JavaScriptFrameIterator it;
4114 it.AdvanceToArgumentsFrame();
4115 JavaScriptFrame* frame = it.frame();
4116
4117 // Get the actual number of provided arguments.
4118 const uint32_t n = frame->GetProvidedParametersCount();
4119
4120 // Try to convert the key to an index. If successful and within
4121 // index return the the argument from the frame.
4122 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004123 if (args[0]->ToArrayIndex(&index) && index < n) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004124 return frame->GetParameter(index);
4125 }
4126
4127 // Convert the key to a string.
4128 HandleScope scope;
4129 bool exception = false;
4130 Handle<Object> converted =
4131 Execution::ToString(args.at<Object>(0), &exception);
4132 if (exception) return Failure::Exception();
4133 Handle<String> key = Handle<String>::cast(converted);
4134
4135 // Try to convert the string key into an array index.
4136 if (key->AsArrayIndex(&index)) {
4137 if (index < n) {
4138 return frame->GetParameter(index);
4139 } else {
4140 return Top::initial_object_prototype()->GetElement(index);
4141 }
4142 }
4143
4144 // Handle special arguments properties.
4145 if (key->Equals(Heap::length_symbol())) return Smi::FromInt(n);
4146 if (key->Equals(Heap::callee_symbol())) return frame->function();
4147
4148 // Lookup in the initial Object.prototype object.
4149 return Top::initial_object_prototype()->GetProperty(*key);
4150}
4151
4152
lrn@chromium.org303ada72010-10-27 09:33:13 +00004153static MaybeObject* Runtime_ToFastProperties(Arguments args) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004154 HandleScope scope;
4155
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004156 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004157 Handle<Object> object = args.at<Object>(0);
4158 if (object->IsJSObject()) {
4159 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
ager@chromium.org5c838252010-02-19 08:53:10 +00004160 if (!js_object->HasFastProperties() && !js_object->IsGlobalObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004161 MaybeObject* ok = js_object->TransformToFastProperties(0);
4162 if (ok->IsRetryAfterGC()) return ok;
ager@chromium.org5c838252010-02-19 08:53:10 +00004163 }
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004164 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004165 return *object;
4166}
4167
4168
lrn@chromium.org303ada72010-10-27 09:33:13 +00004169static MaybeObject* Runtime_ToSlowProperties(Arguments args) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004170 HandleScope scope;
4171
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004172 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004173 Handle<Object> object = args.at<Object>(0);
4174 if (object->IsJSObject()) {
4175 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004176 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004177 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004178 return *object;
4179}
4180
4181
lrn@chromium.org303ada72010-10-27 09:33:13 +00004182static MaybeObject* Runtime_ToBool(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004183 NoHandleAllocation ha;
4184 ASSERT(args.length() == 1);
4185
4186 return args[0]->ToBoolean();
4187}
4188
4189
4190// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
4191// Possible optimizations: put the type string into the oddballs.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004192static MaybeObject* Runtime_Typeof(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004193 NoHandleAllocation ha;
4194
4195 Object* obj = args[0];
4196 if (obj->IsNumber()) return Heap::number_symbol();
4197 HeapObject* heap_obj = HeapObject::cast(obj);
4198
4199 // typeof an undetectable object is 'undefined'
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004200 if (heap_obj->map()->is_undetectable()) return Heap::undefined_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004201
4202 InstanceType instance_type = heap_obj->map()->instance_type();
4203 if (instance_type < FIRST_NONSTRING_TYPE) {
4204 return Heap::string_symbol();
4205 }
4206
4207 switch (instance_type) {
4208 case ODDBALL_TYPE:
4209 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
4210 return Heap::boolean_symbol();
4211 }
4212 if (heap_obj->IsNull()) {
4213 return Heap::object_symbol();
4214 }
4215 ASSERT(heap_obj->IsUndefined());
4216 return Heap::undefined_symbol();
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00004217 case JS_FUNCTION_TYPE: case JS_REGEXP_TYPE:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004218 return Heap::function_symbol();
4219 default:
4220 // For any kind of object not handled above, the spec rule for
4221 // host objects gives that it is okay to return "object"
4222 return Heap::object_symbol();
4223 }
4224}
4225
4226
lrn@chromium.org25156de2010-04-06 13:10:27 +00004227static bool AreDigits(const char*s, int from, int to) {
4228 for (int i = from; i < to; i++) {
4229 if (s[i] < '0' || s[i] > '9') return false;
4230 }
4231
4232 return true;
4233}
4234
4235
4236static int ParseDecimalInteger(const char*s, int from, int to) {
4237 ASSERT(to - from < 10); // Overflow is not possible.
4238 ASSERT(from < to);
4239 int d = s[from] - '0';
4240
4241 for (int i = from + 1; i < to; i++) {
4242 d = 10 * d + (s[i] - '0');
4243 }
4244
4245 return d;
4246}
4247
4248
lrn@chromium.org303ada72010-10-27 09:33:13 +00004249static MaybeObject* Runtime_StringToNumber(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004250 NoHandleAllocation ha;
4251 ASSERT(args.length() == 1);
4252 CONVERT_CHECKED(String, subject, args[0]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004253 subject->TryFlatten();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004254
4255 // Fast case: short integer or some sorts of junk values.
4256 int len = subject->length();
4257 if (subject->IsSeqAsciiString()) {
4258 if (len == 0) return Smi::FromInt(0);
4259
4260 char const* data = SeqAsciiString::cast(subject)->GetChars();
4261 bool minus = (data[0] == '-');
4262 int start_pos = (minus ? 1 : 0);
4263
4264 if (start_pos == len) {
4265 return Heap::nan_value();
4266 } else if (data[start_pos] > '9') {
4267 // Fast check for a junk value. A valid string may start from a
4268 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
4269 // the 'I' character ('Infinity'). All of that have codes not greater than
4270 // '9' except 'I'.
4271 if (data[start_pos] != 'I') {
4272 return Heap::nan_value();
4273 }
4274 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
4275 // The maximal/minimal smi has 10 digits. If the string has less digits we
4276 // know it will fit into the smi-data type.
4277 int d = ParseDecimalInteger(data, start_pos, len);
4278 if (minus) {
4279 if (d == 0) return Heap::minus_zero_value();
4280 d = -d;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004281 } else if (!subject->HasHashCode() &&
4282 len <= String::kMaxArrayIndexSize &&
4283 (len == 1 || data[0] != '0')) {
4284 // String hash is not calculated yet but all the data are present.
4285 // Update the hash field to speed up sequential convertions.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00004286 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004287#ifdef DEBUG
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004288 subject->Hash(); // Force hash calculation.
4289 ASSERT_EQ(static_cast<int>(subject->hash_field()),
4290 static_cast<int>(hash));
4291#endif
4292 subject->set_hash_field(hash);
lrn@chromium.org25156de2010-04-06 13:10:27 +00004293 }
4294 return Smi::FromInt(d);
4295 }
4296 }
4297
4298 // Slower case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004299 return Heap::NumberFromDouble(StringToDouble(subject, ALLOW_HEX));
4300}
4301
4302
lrn@chromium.org303ada72010-10-27 09:33:13 +00004303static MaybeObject* Runtime_StringFromCharCodeArray(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004304 NoHandleAllocation ha;
4305 ASSERT(args.length() == 1);
4306
4307 CONVERT_CHECKED(JSArray, codes, args[0]);
4308 int length = Smi::cast(codes->length())->value();
4309
4310 // Check if the string can be ASCII.
4311 int i;
4312 for (i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004313 Object* element;
4314 { MaybeObject* maybe_element = codes->GetElement(i);
4315 // We probably can't get an exception here, but just in order to enforce
4316 // the checking of inputs in the runtime calls we check here.
4317 if (!maybe_element->ToObject(&element)) return maybe_element;
4318 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004319 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
4320 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
4321 break;
4322 }
4323
lrn@chromium.org303ada72010-10-27 09:33:13 +00004324 MaybeObject* maybe_object = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004325 if (i == length) { // The string is ASCII.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004326 maybe_object = Heap::AllocateRawAsciiString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004327 } else { // The string is not ASCII.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004328 maybe_object = Heap::AllocateRawTwoByteString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004329 }
4330
lrn@chromium.org303ada72010-10-27 09:33:13 +00004331 Object* object = NULL;
4332 if (!maybe_object->ToObject(&object)) return maybe_object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004333 String* result = String::cast(object);
4334 for (int i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004335 Object* element;
4336 { MaybeObject* maybe_element = codes->GetElement(i);
4337 if (!maybe_element->ToObject(&element)) return maybe_element;
4338 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004339 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004340 result->Set(i, chr & 0xffff);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004341 }
4342 return result;
4343}
4344
4345
4346// kNotEscaped is generated by the following:
4347//
4348// #!/bin/perl
4349// for (my $i = 0; $i < 256; $i++) {
4350// print "\n" if $i % 16 == 0;
4351// my $c = chr($i);
4352// my $escaped = 1;
4353// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
4354// print $escaped ? "0, " : "1, ";
4355// }
4356
4357
4358static bool IsNotEscaped(uint16_t character) {
4359 // Only for 8 bit characters, the rest are always escaped (in a different way)
4360 ASSERT(character < 256);
4361 static const char kNotEscaped[256] = {
4362 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4363 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4364 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
4365 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
4366 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4367 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
4368 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4369 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4375 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4376 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4377 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4378 };
4379 return kNotEscaped[character] != 0;
4380}
4381
4382
lrn@chromium.org303ada72010-10-27 09:33:13 +00004383static MaybeObject* Runtime_URIEscape(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004384 const char hex_chars[] = "0123456789ABCDEF";
4385 NoHandleAllocation ha;
4386 ASSERT(args.length() == 1);
4387 CONVERT_CHECKED(String, source, args[0]);
4388
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004389 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004390
4391 int escaped_length = 0;
4392 int length = source->length();
4393 {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004394 Access<StringInputBuffer> buffer(&runtime_string_input_buffer);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004395 buffer->Reset(source);
4396 while (buffer->has_more()) {
4397 uint16_t character = buffer->GetNext();
4398 if (character >= 256) {
4399 escaped_length += 6;
4400 } else if (IsNotEscaped(character)) {
4401 escaped_length++;
4402 } else {
4403 escaped_length += 3;
4404 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004405 // We don't allow strings that are longer than a maximal length.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004406 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004407 if (escaped_length > String::kMaxLength) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004408 Top::context()->mark_out_of_memory();
4409 return Failure::OutOfMemoryException();
4410 }
4411 }
4412 }
4413 // No length change implies no change. Return original string if no change.
4414 if (escaped_length == length) {
4415 return source;
4416 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00004417 Object* o;
4418 { MaybeObject* maybe_o = Heap::AllocateRawAsciiString(escaped_length);
4419 if (!maybe_o->ToObject(&o)) return maybe_o;
4420 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004421 String* destination = String::cast(o);
4422 int dest_position = 0;
4423
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004424 Access<StringInputBuffer> buffer(&runtime_string_input_buffer);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004425 buffer->Rewind();
4426 while (buffer->has_more()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00004427 uint16_t chr = buffer->GetNext();
4428 if (chr >= 256) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004429 destination->Set(dest_position, '%');
4430 destination->Set(dest_position+1, 'u');
4431 destination->Set(dest_position+2, hex_chars[chr >> 12]);
4432 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]);
4433 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]);
4434 destination->Set(dest_position+5, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004435 dest_position += 6;
ager@chromium.org870a0b62008-11-04 11:43:05 +00004436 } else if (IsNotEscaped(chr)) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004437 destination->Set(dest_position, chr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004438 dest_position++;
4439 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004440 destination->Set(dest_position, '%');
4441 destination->Set(dest_position+1, hex_chars[chr >> 4]);
4442 destination->Set(dest_position+2, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004443 dest_position += 3;
4444 }
4445 }
4446 return destination;
4447}
4448
4449
4450static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
4451 static const signed char kHexValue['g'] = {
4452 -1, -1, -1, -1, -1, -1, -1, -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, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4455 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
4456 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4457 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4458 -1, 10, 11, 12, 13, 14, 15 };
4459
4460 if (character1 > 'f') return -1;
4461 int hi = kHexValue[character1];
4462 if (hi == -1) return -1;
4463 if (character2 > 'f') return -1;
4464 int lo = kHexValue[character2];
4465 if (lo == -1) return -1;
4466 return (hi << 4) + lo;
4467}
4468
4469
ager@chromium.org870a0b62008-11-04 11:43:05 +00004470static inline int Unescape(String* source,
ager@chromium.org870a0b62008-11-04 11:43:05 +00004471 int i,
4472 int length,
4473 int* step) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004474 uint16_t character = source->Get(i);
ager@chromium.org870a0b62008-11-04 11:43:05 +00004475 int32_t hi = 0;
4476 int32_t lo = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004477 if (character == '%' &&
4478 i <= length - 6 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004479 source->Get(i + 1) == 'u' &&
4480 (hi = TwoDigitHex(source->Get(i + 2),
4481 source->Get(i + 3))) != -1 &&
4482 (lo = TwoDigitHex(source->Get(i + 4),
4483 source->Get(i + 5))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004484 *step = 6;
4485 return (hi << 8) + lo;
4486 } else if (character == '%' &&
4487 i <= length - 3 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004488 (lo = TwoDigitHex(source->Get(i + 1),
4489 source->Get(i + 2))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004490 *step = 3;
4491 return lo;
4492 } else {
4493 *step = 1;
4494 return character;
4495 }
4496}
4497
4498
lrn@chromium.org303ada72010-10-27 09:33:13 +00004499static MaybeObject* Runtime_URIUnescape(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004500 NoHandleAllocation ha;
4501 ASSERT(args.length() == 1);
4502 CONVERT_CHECKED(String, source, args[0]);
4503
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004504 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004505
4506 bool ascii = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004507 int length = source->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004508
4509 int unescaped_length = 0;
4510 for (int i = 0; i < length; unescaped_length++) {
4511 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004512 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004513 ascii = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004514 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004515 i += step;
4516 }
4517
4518 // No length change implies no change. Return original string if no change.
4519 if (unescaped_length == length)
4520 return source;
4521
lrn@chromium.org303ada72010-10-27 09:33:13 +00004522 Object* o;
4523 { MaybeObject* maybe_o = ascii ?
4524 Heap::AllocateRawAsciiString(unescaped_length) :
4525 Heap::AllocateRawTwoByteString(unescaped_length);
4526 if (!maybe_o->ToObject(&o)) return maybe_o;
4527 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004528 String* destination = String::cast(o);
4529
4530 int dest_position = 0;
4531 for (int i = 0; i < length; dest_position++) {
4532 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004533 destination->Set(dest_position, Unescape(source, i, length, &step));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004534 i += step;
4535 }
4536 return destination;
4537}
4538
4539
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004540static const unsigned int kQuoteTableLength = 128u;
4541
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004542static const int kJsonQuotesCharactersPerEntry = 8;
4543static const char* const JsonQuotes =
4544 "\\u0000 \\u0001 \\u0002 \\u0003 "
4545 "\\u0004 \\u0005 \\u0006 \\u0007 "
4546 "\\b \\t \\n \\u000b "
4547 "\\f \\r \\u000e \\u000f "
4548 "\\u0010 \\u0011 \\u0012 \\u0013 "
4549 "\\u0014 \\u0015 \\u0016 \\u0017 "
4550 "\\u0018 \\u0019 \\u001a \\u001b "
4551 "\\u001c \\u001d \\u001e \\u001f "
4552 " ! \\\" # "
4553 "$ % & ' "
4554 "( ) * + "
4555 ", - . / "
4556 "0 1 2 3 "
4557 "4 5 6 7 "
4558 "8 9 : ; "
4559 "< = > ? "
4560 "@ A B C "
4561 "D E F G "
4562 "H I J K "
4563 "L M N O "
4564 "P Q R S "
4565 "T U V W "
4566 "X Y Z [ "
4567 "\\\\ ] ^ _ "
4568 "` a b c "
4569 "d e f g "
4570 "h i j k "
4571 "l m n o "
4572 "p q r s "
4573 "t u v w "
4574 "x y z { "
4575 "| } ~ \177 ";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004576
4577
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004578// For a string that is less than 32k characters it should always be
4579// possible to allocate it in new space.
4580static const int kMaxGuaranteedNewSpaceString = 32 * 1024;
4581
4582
4583// Doing JSON quoting cannot make the string more than this many times larger.
4584static const int kJsonQuoteWorstCaseBlowup = 6;
4585
4586
4587// Covers the entire ASCII range (all other characters are unchanged by JSON
4588// quoting).
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004589static const byte JsonQuoteLengths[kQuoteTableLength] = {
4590 6, 6, 6, 6, 6, 6, 6, 6,
4591 2, 2, 2, 6, 2, 2, 6, 6,
4592 6, 6, 6, 6, 6, 6, 6, 6,
4593 6, 6, 6, 6, 6, 6, 6, 6,
4594 1, 1, 2, 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, 1, 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, 2, 1, 1, 1,
4602 1, 1, 1, 1, 1, 1, 1, 1,
4603 1, 1, 1, 1, 1, 1, 1, 1,
4604 1, 1, 1, 1, 1, 1, 1, 1,
4605 1, 1, 1, 1, 1, 1, 1, 1,
4606};
4607
4608
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004609template <typename StringType>
4610MaybeObject* AllocateRawString(int length);
4611
4612
4613template <>
4614MaybeObject* AllocateRawString<SeqTwoByteString>(int length) {
4615 return Heap::AllocateRawTwoByteString(length);
4616}
4617
4618
4619template <>
4620MaybeObject* AllocateRawString<SeqAsciiString>(int length) {
4621 return Heap::AllocateRawAsciiString(length);
4622}
4623
4624
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004625template <typename Char, typename StringType, bool comma>
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004626static MaybeObject* SlowQuoteJsonString(Vector<const Char> characters) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004627 int length = characters.length();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004628 const Char* read_cursor = characters.start();
4629 const Char* end = read_cursor + length;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004630 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004631 int quoted_length = kSpaceForQuotes;
4632 while (read_cursor < end) {
4633 Char c = *(read_cursor++);
4634 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
4635 quoted_length++;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004636 } else {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004637 quoted_length += JsonQuoteLengths[static_cast<unsigned>(c)];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004638 }
4639 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004640 MaybeObject* new_alloc = AllocateRawString<StringType>(quoted_length);
4641 Object* new_object;
4642 if (!new_alloc->ToObject(&new_object)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004643 return new_alloc;
4644 }
4645 StringType* new_string = StringType::cast(new_object);
4646
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004647 Char* write_cursor = reinterpret_cast<Char*>(
4648 new_string->address() + SeqAsciiString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004649 if (comma) *(write_cursor++) = ',';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004650 *(write_cursor++) = '"';
4651
4652 read_cursor = characters.start();
4653 while (read_cursor < end) {
4654 Char c = *(read_cursor++);
4655 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
4656 *(write_cursor++) = c;
4657 } else {
4658 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
4659 const char* replacement = JsonQuotes +
4660 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
4661 for (int i = 0; i < len; i++) {
4662 *write_cursor++ = *replacement++;
4663 }
4664 }
4665 }
4666 *(write_cursor++) = '"';
4667 return new_string;
4668}
4669
4670
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004671template <typename Char, typename StringType, bool comma>
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004672static MaybeObject* QuoteJsonString(Vector<const Char> characters) {
4673 int length = characters.length();
4674 Counters::quote_json_char_count.Increment(length);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004675 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004676 int worst_case_length = length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotes;
4677 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004678 return SlowQuoteJsonString<Char, StringType, comma>(characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004679 }
4680
4681 MaybeObject* new_alloc = AllocateRawString<StringType>(worst_case_length);
4682 Object* new_object;
4683 if (!new_alloc->ToObject(&new_object)) {
4684 return new_alloc;
4685 }
4686 if (!Heap::new_space()->Contains(new_object)) {
4687 // Even if our string is small enough to fit in new space we still have to
4688 // handle it being allocated in old space as may happen in the third
4689 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
4690 // CEntryStub::GenerateCore.
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004691 return SlowQuoteJsonString<Char, StringType, comma>(characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004692 }
4693 StringType* new_string = StringType::cast(new_object);
4694 ASSERT(Heap::new_space()->Contains(new_string));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004695
4696 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize);
4697 Char* write_cursor = reinterpret_cast<Char*>(
4698 new_string->address() + SeqAsciiString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004699 if (comma) *(write_cursor++) = ',';
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004700 *(write_cursor++) = '"';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004701
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004702 const Char* read_cursor = characters.start();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004703 const Char* end = read_cursor + length;
4704 while (read_cursor < end) {
4705 Char c = *(read_cursor++);
4706 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
4707 *(write_cursor++) = c;
4708 } else {
4709 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
4710 const char* replacement = JsonQuotes +
4711 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
4712 write_cursor[0] = replacement[0];
4713 if (len > 1) {
4714 write_cursor[1] = replacement[1];
4715 if (len > 2) {
4716 ASSERT(len == 6);
4717 write_cursor[2] = replacement[2];
4718 write_cursor[3] = replacement[3];
4719 write_cursor[4] = replacement[4];
4720 write_cursor[5] = replacement[5];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004721 }
4722 }
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004723 write_cursor += len;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004724 }
4725 }
4726 *(write_cursor++) = '"';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004727
4728 int final_length = static_cast<int>(
4729 write_cursor - reinterpret_cast<Char*>(
4730 new_string->address() + SeqAsciiString::kHeaderSize));
4731 Heap::new_space()->ShrinkStringAtAllocationBoundary<StringType>(new_string,
4732 final_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004733 return new_string;
4734}
4735
4736
4737static MaybeObject* Runtime_QuoteJSONString(Arguments args) {
4738 NoHandleAllocation ha;
4739 CONVERT_CHECKED(String, str, args[0]);
4740 if (!str->IsFlat()) {
4741 MaybeObject* try_flatten = str->TryFlatten();
4742 Object* flat;
4743 if (!try_flatten->ToObject(&flat)) {
4744 return try_flatten;
4745 }
4746 str = String::cast(flat);
4747 ASSERT(str->IsFlat());
4748 }
4749 if (str->IsTwoByteRepresentation()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004750 return QuoteJsonString<uc16, SeqTwoByteString, false>(str->ToUC16Vector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004751 } else {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004752 return QuoteJsonString<char, SeqAsciiString, false>(str->ToAsciiVector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004753 }
4754}
4755
4756
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004757static MaybeObject* Runtime_QuoteJSONStringComma(Arguments args) {
4758 NoHandleAllocation ha;
4759 CONVERT_CHECKED(String, str, args[0]);
4760 if (!str->IsFlat()) {
4761 MaybeObject* try_flatten = str->TryFlatten();
4762 Object* flat;
4763 if (!try_flatten->ToObject(&flat)) {
4764 return try_flatten;
4765 }
4766 str = String::cast(flat);
4767 ASSERT(str->IsFlat());
4768 }
4769 if (str->IsTwoByteRepresentation()) {
4770 return QuoteJsonString<uc16, SeqTwoByteString, true>(str->ToUC16Vector());
4771 } else {
4772 return QuoteJsonString<char, SeqAsciiString, true>(str->ToAsciiVector());
4773 }
4774}
4775
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004776
lrn@chromium.org303ada72010-10-27 09:33:13 +00004777static MaybeObject* Runtime_StringParseInt(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004778 NoHandleAllocation ha;
4779
4780 CONVERT_CHECKED(String, s, args[0]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00004781 CONVERT_SMI_CHECKED(radix, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004782
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004783 s->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004784
lrn@chromium.org25156de2010-04-06 13:10:27 +00004785 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
4786 double value = StringToInt(s, radix);
4787 return Heap::NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004788}
4789
4790
lrn@chromium.org303ada72010-10-27 09:33:13 +00004791static MaybeObject* Runtime_StringParseFloat(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004792 NoHandleAllocation ha;
4793 CONVERT_CHECKED(String, str, args[0]);
4794
4795 // ECMA-262 section 15.1.2.3, empty string is NaN
4796 double value = StringToDouble(str, ALLOW_TRAILING_JUNK, OS::nan_value());
4797
4798 // Create a number object from the value.
4799 return Heap::NumberFromDouble(value);
4800}
4801
4802
4803static unibrow::Mapping<unibrow::ToUppercase, 128> to_upper_mapping;
4804static unibrow::Mapping<unibrow::ToLowercase, 128> to_lower_mapping;
4805
4806
4807template <class Converter>
lrn@chromium.org303ada72010-10-27 09:33:13 +00004808MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
4809 String* s,
4810 int length,
4811 int input_string_length,
4812 unibrow::Mapping<Converter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004813 // We try this twice, once with the assumption that the result is no longer
4814 // than the input and, if that assumption breaks, again with the exact
4815 // length. This may not be pretty, but it is nicer than what was here before
4816 // and I hereby claim my vaffel-is.
4817 //
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004818 // Allocate the resulting string.
4819 //
4820 // NOTE: This assumes that the upper/lower case of an ascii
4821 // character is also ascii. This is currently the case, but it
4822 // might break in the future if we implement more context and locale
4823 // dependent upper/lower conversions.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004824 Object* o;
4825 { MaybeObject* maybe_o = s->IsAsciiRepresentation()
4826 ? Heap::AllocateRawAsciiString(length)
4827 : Heap::AllocateRawTwoByteString(length);
4828 if (!maybe_o->ToObject(&o)) return maybe_o;
4829 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004830 String* result = String::cast(o);
4831 bool has_changed_character = false;
4832
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004833 // Convert all characters to upper case, assuming that they will fit
4834 // in the buffer
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004835 Access<StringInputBuffer> buffer(&runtime_string_input_buffer);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004836 buffer->Reset(s);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004837 unibrow::uchar chars[Converter::kMaxWidth];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004838 // We can assume that the string is not empty
4839 uc32 current = buffer->GetNext();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004840 for (int i = 0; i < length;) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00004841 bool has_next = buffer->has_more();
4842 uc32 next = has_next ? buffer->GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004843 int char_length = mapping->get(current, next, chars);
4844 if (char_length == 0) {
4845 // The case conversion of this character is the character itself.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004846 result->Set(i, current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004847 i++;
4848 } else if (char_length == 1) {
4849 // Common case: converting the letter resulted in one character.
4850 ASSERT(static_cast<uc32>(chars[0]) != current);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004851 result->Set(i, chars[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004852 has_changed_character = true;
4853 i++;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004854 } else if (length == input_string_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004855 // We've assumed that the result would be as long as the
4856 // input but here is a character that converts to several
4857 // characters. No matter, we calculate the exact length
4858 // of the result and try the whole thing again.
4859 //
4860 // Note that this leaves room for optimization. We could just
4861 // memcpy what we already have to the result string. Also,
4862 // the result string is the last object allocated we could
4863 // "realloc" it and probably, in the vast majority of cases,
4864 // extend the existing string to be able to hold the full
4865 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00004866 int next_length = 0;
4867 if (has_next) {
4868 next_length = mapping->get(next, 0, chars);
4869 if (next_length == 0) next_length = 1;
4870 }
4871 int current_length = i + char_length + next_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004872 while (buffer->has_more()) {
4873 current = buffer->GetNext();
ager@chromium.org7c537e22008-10-16 08:43:32 +00004874 // NOTE: we use 0 as the next character here because, while
4875 // the next character may affect what a character converts to,
4876 // it does not in any case affect the length of what it convert
4877 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004878 int char_length = mapping->get(current, 0, chars);
4879 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00004880 current_length += char_length;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004881 if (current_length > Smi::kMaxValue) {
4882 Top::context()->mark_out_of_memory();
4883 return Failure::OutOfMemoryException();
4884 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004885 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004886 // Try again with the real length.
4887 return Smi::FromInt(current_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004888 } else {
4889 for (int j = 0; j < char_length; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004890 result->Set(i, chars[j]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004891 i++;
4892 }
4893 has_changed_character = true;
4894 }
4895 current = next;
4896 }
4897 if (has_changed_character) {
4898 return result;
4899 } else {
4900 // If we didn't actually change anything in doing the conversion
4901 // we simple return the result and let the converted string
4902 // become garbage; there is no reason to keep two identical strings
4903 // alive.
4904 return s;
4905 }
4906}
4907
4908
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004909namespace {
4910
lrn@chromium.org303ada72010-10-27 09:33:13 +00004911static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF;
4912
4913
4914// Given a word and two range boundaries returns a word with high bit
4915// set in every byte iff the corresponding input byte was strictly in
4916// the range (m, n). All the other bits in the result are cleared.
4917// This function is only useful when it can be inlined and the
4918// boundaries are statically known.
4919// Requires: all bytes in the input word and the boundaries must be
4920// ascii (less than 0x7F).
4921static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
4922 // Every byte in an ascii string is less than or equal to 0x7F.
4923 ASSERT((w & (kOneInEveryByte * 0x7F)) == w);
4924 // Use strict inequalities since in edge cases the function could be
4925 // further simplified.
4926 ASSERT(0 < m && m < n && n < 0x7F);
4927 // Has high bit set in every w byte less than n.
4928 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w;
4929 // Has high bit set in every w byte greater than m.
4930 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m);
4931 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80));
4932}
4933
4934
4935enum AsciiCaseConversion {
4936 ASCII_TO_LOWER,
4937 ASCII_TO_UPPER
4938};
4939
4940
4941template <AsciiCaseConversion dir>
4942struct FastAsciiConverter {
4943 static bool Convert(char* dst, char* src, int length) {
4944#ifdef DEBUG
4945 char* saved_dst = dst;
4946 char* saved_src = src;
4947#endif
4948 // We rely on the distance between upper and lower case letters
4949 // being a known power of 2.
4950 ASSERT('a' - 'A' == (1 << 5));
4951 // Boundaries for the range of input characters than require conversion.
4952 const char lo = (dir == ASCII_TO_LOWER) ? 'A' - 1 : 'a' - 1;
4953 const char hi = (dir == ASCII_TO_LOWER) ? 'Z' + 1 : 'z' + 1;
4954 bool changed = false;
4955 char* const limit = src + length;
4956#ifdef V8_HOST_CAN_READ_UNALIGNED
4957 // Process the prefix of the input that requires no conversion one
4958 // (machine) word at a time.
4959 while (src <= limit - sizeof(uintptr_t)) {
4960 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
4961 if (AsciiRangeMask(w, lo, hi) != 0) {
4962 changed = true;
4963 break;
4964 }
4965 *reinterpret_cast<uintptr_t*>(dst) = w;
4966 src += sizeof(uintptr_t);
4967 dst += sizeof(uintptr_t);
4968 }
4969 // Process the remainder of the input performing conversion when
4970 // required one word at a time.
4971 while (src <= limit - sizeof(uintptr_t)) {
4972 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
4973 uintptr_t m = AsciiRangeMask(w, lo, hi);
4974 // The mask has high (7th) bit set in every byte that needs
4975 // conversion and we know that the distance between cases is
4976 // 1 << 5.
4977 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
4978 src += sizeof(uintptr_t);
4979 dst += sizeof(uintptr_t);
4980 }
4981#endif
4982 // Process the last few bytes of the input (or the whole input if
4983 // unaligned access is not supported).
4984 while (src < limit) {
4985 char c = *src;
4986 if (lo < c && c < hi) {
4987 c ^= (1 << 5);
4988 changed = true;
4989 }
4990 *dst = c;
4991 ++src;
4992 ++dst;
4993 }
4994#ifdef DEBUG
4995 CheckConvert(saved_dst, saved_src, length, changed);
4996#endif
4997 return changed;
4998 }
4999
5000#ifdef DEBUG
5001 static void CheckConvert(char* dst, char* src, int length, bool changed) {
5002 bool expected_changed = false;
5003 for (int i = 0; i < length; i++) {
5004 if (dst[i] == src[i]) continue;
5005 expected_changed = true;
5006 if (dir == ASCII_TO_LOWER) {
5007 ASSERT('A' <= src[i] && src[i] <= 'Z');
5008 ASSERT(dst[i] == src[i] + ('a' - 'A'));
5009 } else {
5010 ASSERT(dir == ASCII_TO_UPPER);
5011 ASSERT('a' <= src[i] && src[i] <= 'z');
5012 ASSERT(dst[i] == src[i] - ('a' - 'A'));
5013 }
5014 }
5015 ASSERT(expected_changed == changed);
5016 }
5017#endif
5018};
5019
5020
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005021struct ToLowerTraits {
5022 typedef unibrow::ToLowercase UnibrowConverter;
5023
lrn@chromium.org303ada72010-10-27 09:33:13 +00005024 typedef FastAsciiConverter<ASCII_TO_LOWER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005025};
5026
5027
5028struct ToUpperTraits {
5029 typedef unibrow::ToUppercase UnibrowConverter;
5030
lrn@chromium.org303ada72010-10-27 09:33:13 +00005031 typedef FastAsciiConverter<ASCII_TO_UPPER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005032};
5033
5034} // namespace
5035
5036
5037template <typename ConvertTraits>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005038MUST_USE_RESULT static MaybeObject* ConvertCase(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005039 Arguments args,
5040 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005041 NoHandleAllocation ha;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005042 CONVERT_CHECKED(String, s, args[0]);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005043 s = s->TryFlattenGetString();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005044
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005045 const int length = s->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005046 // Assume that the string is not empty; we need this assumption later
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005047 if (length == 0) return s;
5048
5049 // Simpler handling of ascii strings.
5050 //
5051 // NOTE: This assumes that the upper/lower case of an ascii
5052 // character is also ascii. This is currently the case, but it
5053 // might break in the future if we implement more context and locale
5054 // dependent upper/lower conversions.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005055 if (s->IsSeqAsciiString()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005056 Object* o;
5057 { MaybeObject* maybe_o = Heap::AllocateRawAsciiString(length);
5058 if (!maybe_o->ToObject(&o)) return maybe_o;
5059 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005060 SeqAsciiString* result = SeqAsciiString::cast(o);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005061 bool has_changed_character = ConvertTraits::AsciiConverter::Convert(
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005062 result->GetChars(), SeqAsciiString::cast(s)->GetChars(), length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005063 return has_changed_character ? result : s;
5064 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005065
lrn@chromium.org303ada72010-10-27 09:33:13 +00005066 Object* answer;
5067 { MaybeObject* maybe_answer = ConvertCaseHelper(s, length, length, mapping);
5068 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5069 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005070 if (answer->IsSmi()) {
5071 // Retry with correct length.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005072 { MaybeObject* maybe_answer =
5073 ConvertCaseHelper(s, Smi::cast(answer)->value(), length, mapping);
5074 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5075 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005076 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00005077 return answer;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005078}
5079
5080
lrn@chromium.org303ada72010-10-27 09:33:13 +00005081static MaybeObject* Runtime_StringToLowerCase(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005082 return ConvertCase<ToLowerTraits>(args, &to_lower_mapping);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005083}
5084
5085
lrn@chromium.org303ada72010-10-27 09:33:13 +00005086static MaybeObject* Runtime_StringToUpperCase(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005087 return ConvertCase<ToUpperTraits>(args, &to_upper_mapping);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005088}
5089
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005090
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005091static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
5092 return unibrow::WhiteSpace::Is(c) || c == 0x200b;
5093}
5094
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005095
lrn@chromium.org303ada72010-10-27 09:33:13 +00005096static MaybeObject* Runtime_StringTrim(Arguments args) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005097 NoHandleAllocation ha;
5098 ASSERT(args.length() == 3);
5099
5100 CONVERT_CHECKED(String, s, args[0]);
5101 CONVERT_BOOLEAN_CHECKED(trimLeft, args[1]);
5102 CONVERT_BOOLEAN_CHECKED(trimRight, args[2]);
5103
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005104 s->TryFlatten();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005105 int length = s->length();
5106
5107 int left = 0;
5108 if (trimLeft) {
5109 while (left < length && IsTrimWhiteSpace(s->Get(left))) {
5110 left++;
5111 }
5112 }
5113
5114 int right = length;
5115 if (trimRight) {
5116 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) {
5117 right--;
5118 }
5119 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005120 return s->SubString(left, right);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005121}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005122
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005123
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005124template <typename SubjectChar, typename PatternChar>
5125void FindStringIndices(Vector<const SubjectChar> subject,
5126 Vector<const PatternChar> pattern,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005127 ZoneList<int>* indices,
5128 unsigned int limit) {
5129 ASSERT(limit > 0);
5130 // Collect indices of pattern in subject, and the end-of-string index.
5131 // Stop after finding at most limit values.
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005132 StringSearch<PatternChar, SubjectChar> search(pattern);
5133 int pattern_length = pattern.length();
5134 int index = 0;
5135 while (limit > 0) {
5136 index = search.Search(subject, index);
5137 if (index < 0) return;
5138 indices->Add(index);
5139 index += pattern_length;
5140 limit--;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005141 }
5142}
5143
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005144
lrn@chromium.org303ada72010-10-27 09:33:13 +00005145static MaybeObject* Runtime_StringSplit(Arguments args) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005146 ASSERT(args.length() == 3);
5147 HandleScope handle_scope;
5148 CONVERT_ARG_CHECKED(String, subject, 0);
5149 CONVERT_ARG_CHECKED(String, pattern, 1);
5150 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
5151
5152 int subject_length = subject->length();
5153 int pattern_length = pattern->length();
5154 RUNTIME_ASSERT(pattern_length > 0);
5155
5156 // The limit can be very large (0xffffffffu), but since the pattern
5157 // isn't empty, we can never create more parts than ~half the length
5158 // of the subject.
5159
5160 if (!subject->IsFlat()) FlattenString(subject);
5161
5162 static const int kMaxInitialListCapacity = 16;
5163
5164 ZoneScope scope(DELETE_ON_EXIT);
5165
5166 // Find (up to limit) indices of separator and end-of-string in subject
5167 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
5168 ZoneList<int> indices(initial_capacity);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005169 if (!pattern->IsFlat()) FlattenString(pattern);
5170
5171 // No allocation block.
5172 {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005173 AssertNoAllocation nogc;
5174 if (subject->IsAsciiRepresentation()) {
5175 Vector<const char> subject_vector = subject->ToAsciiVector();
5176 if (pattern->IsAsciiRepresentation()) {
5177 FindStringIndices(subject_vector,
5178 pattern->ToAsciiVector(),
5179 &indices,
5180 limit);
5181 } else {
5182 FindStringIndices(subject_vector,
5183 pattern->ToUC16Vector(),
5184 &indices,
5185 limit);
5186 }
5187 } else {
5188 Vector<const uc16> subject_vector = subject->ToUC16Vector();
5189 if (pattern->IsAsciiRepresentation()) {
5190 FindStringIndices(subject_vector,
5191 pattern->ToAsciiVector(),
5192 &indices,
5193 limit);
5194 } else {
5195 FindStringIndices(subject_vector,
5196 pattern->ToUC16Vector(),
5197 &indices,
5198 limit);
5199 }
5200 }
5201 }
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005202
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005203 if (static_cast<uint32_t>(indices.length()) < limit) {
5204 indices.Add(subject_length);
5205 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005206
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005207 // The list indices now contains the end of each part to create.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005208
5209 // Create JSArray of substrings separated by separator.
5210 int part_count = indices.length();
5211
5212 Handle<JSArray> result = Factory::NewJSArray(part_count);
5213 result->set_length(Smi::FromInt(part_count));
5214
5215 ASSERT(result->HasFastElements());
5216
5217 if (part_count == 1 && indices.at(0) == subject_length) {
5218 FixedArray::cast(result->elements())->set(0, *subject);
5219 return *result;
5220 }
5221
5222 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
5223 int part_start = 0;
5224 for (int i = 0; i < part_count; i++) {
5225 HandleScope local_loop_handle;
5226 int part_end = indices.at(i);
5227 Handle<String> substring =
5228 Factory::NewSubString(subject, part_start, part_end);
5229 elements->set(i, *substring);
5230 part_start = part_end + pattern_length;
5231 }
5232
5233 return *result;
5234}
5235
5236
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005237// Copies ascii characters to the given fixed array looking up
5238// one-char strings in the cache. Gives up on the first char that is
5239// not in the cache and fills the remainder with smi zeros. Returns
5240// the length of the successfully copied prefix.
5241static int CopyCachedAsciiCharsToArray(const char* chars,
5242 FixedArray* elements,
5243 int length) {
5244 AssertNoAllocation nogc;
5245 FixedArray* ascii_cache = Heap::single_character_string_cache();
5246 Object* undefined = Heap::undefined_value();
5247 int i;
5248 for (i = 0; i < length; ++i) {
5249 Object* value = ascii_cache->get(chars[i]);
5250 if (value == undefined) break;
5251 ASSERT(!Heap::InNewSpace(value));
5252 elements->set(i, value, SKIP_WRITE_BARRIER);
5253 }
5254 if (i < length) {
5255 ASSERT(Smi::FromInt(0) == 0);
5256 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
5257 }
5258#ifdef DEBUG
5259 for (int j = 0; j < length; ++j) {
5260 Object* element = elements->get(j);
5261 ASSERT(element == Smi::FromInt(0) ||
5262 (element->IsString() && String::cast(element)->LooksValid()));
5263 }
5264#endif
5265 return i;
5266}
5267
5268
5269// Converts a String to JSArray.
5270// For example, "foo" => ["f", "o", "o"].
lrn@chromium.org303ada72010-10-27 09:33:13 +00005271static MaybeObject* Runtime_StringToArray(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005272 HandleScope scope;
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005273 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005274 CONVERT_ARG_CHECKED(String, s, 0);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005275 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005276
5277 s->TryFlatten();
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005278 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005279
5280 Handle<FixedArray> elements;
5281 if (s->IsFlat() && s->IsAsciiRepresentation()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005282 Object* obj;
5283 { MaybeObject* maybe_obj = Heap::AllocateUninitializedFixedArray(length);
5284 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5285 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005286 elements = Handle<FixedArray>(FixedArray::cast(obj));
5287
5288 Vector<const char> chars = s->ToAsciiVector();
5289 // Note, this will initialize all elements (not only the prefix)
5290 // to prevent GC from seeing partially initialized array.
5291 int num_copied_from_cache = CopyCachedAsciiCharsToArray(chars.start(),
5292 *elements,
5293 length);
5294
5295 for (int i = num_copied_from_cache; i < length; ++i) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00005296 Handle<Object> str = LookupSingleCharacterStringFromCode(chars[i]);
5297 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005298 }
5299 } else {
5300 elements = Factory::NewFixedArray(length);
5301 for (int i = 0; i < length; ++i) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00005302 Handle<Object> str = LookupSingleCharacterStringFromCode(s->Get(i));
5303 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005304 }
5305 }
5306
5307#ifdef DEBUG
5308 for (int i = 0; i < length; ++i) {
5309 ASSERT(String::cast(elements->get(i))->length() == 1);
5310 }
5311#endif
5312
5313 return *Factory::NewJSArrayWithElements(elements);
5314}
5315
5316
lrn@chromium.org303ada72010-10-27 09:33:13 +00005317static MaybeObject* Runtime_NewStringWrapper(Arguments args) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005318 NoHandleAllocation ha;
5319 ASSERT(args.length() == 1);
5320 CONVERT_CHECKED(String, value, args[0]);
5321 return value->ToObject();
5322}
5323
5324
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00005325bool Runtime::IsUpperCaseChar(uint16_t ch) {
5326 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
5327 int char_length = to_upper_mapping.get(ch, 0, chars);
5328 return char_length == 0;
5329}
5330
5331
lrn@chromium.org303ada72010-10-27 09:33:13 +00005332static MaybeObject* Runtime_NumberToString(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005333 NoHandleAllocation ha;
5334 ASSERT(args.length() == 1);
5335
5336 Object* number = args[0];
5337 RUNTIME_ASSERT(number->IsNumber());
5338
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005339 return Heap::NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005340}
5341
5342
lrn@chromium.org303ada72010-10-27 09:33:13 +00005343static MaybeObject* Runtime_NumberToStringSkipCache(Arguments args) {
ager@chromium.org357bf652010-04-12 11:30:10 +00005344 NoHandleAllocation ha;
5345 ASSERT(args.length() == 1);
5346
5347 Object* number = args[0];
5348 RUNTIME_ASSERT(number->IsNumber());
5349
5350 return Heap::NumberToString(number, false);
5351}
5352
5353
lrn@chromium.org303ada72010-10-27 09:33:13 +00005354static MaybeObject* Runtime_NumberToInteger(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005355 NoHandleAllocation ha;
5356 ASSERT(args.length() == 1);
5357
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005358 CONVERT_DOUBLE_CHECKED(number, args[0]);
5359
5360 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5361 if (number > 0 && number <= Smi::kMaxValue) {
5362 return Smi::FromInt(static_cast<int>(number));
5363 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005364 return Heap::NumberFromDouble(DoubleToInteger(number));
5365}
5366
5367
lrn@chromium.org303ada72010-10-27 09:33:13 +00005368static MaybeObject* Runtime_NumberToIntegerMapMinusZero(Arguments args) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005369 NoHandleAllocation ha;
5370 ASSERT(args.length() == 1);
5371
5372 CONVERT_DOUBLE_CHECKED(number, args[0]);
5373
5374 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5375 if (number > 0 && number <= Smi::kMaxValue) {
5376 return Smi::FromInt(static_cast<int>(number));
5377 }
5378
5379 double double_value = DoubleToInteger(number);
5380 // Map both -0 and +0 to +0.
5381 if (double_value == 0) double_value = 0;
5382
5383 return Heap::NumberFromDouble(double_value);
5384}
5385
5386
lrn@chromium.org303ada72010-10-27 09:33:13 +00005387static MaybeObject* Runtime_NumberToJSUint32(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005388 NoHandleAllocation ha;
5389 ASSERT(args.length() == 1);
5390
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005391 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005392 return Heap::NumberFromUint32(number);
5393}
5394
5395
lrn@chromium.org303ada72010-10-27 09:33:13 +00005396static MaybeObject* Runtime_NumberToJSInt32(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005397 NoHandleAllocation ha;
5398 ASSERT(args.length() == 1);
5399
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005400 CONVERT_DOUBLE_CHECKED(number, args[0]);
5401
5402 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5403 if (number > 0 && number <= Smi::kMaxValue) {
5404 return Smi::FromInt(static_cast<int>(number));
5405 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005406 return Heap::NumberFromInt32(DoubleToInt32(number));
5407}
5408
5409
ager@chromium.org870a0b62008-11-04 11:43:05 +00005410// Converts a Number to a Smi, if possible. Returns NaN if the number is not
5411// a small integer.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005412static MaybeObject* Runtime_NumberToSmi(Arguments args) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00005413 NoHandleAllocation ha;
5414 ASSERT(args.length() == 1);
5415
5416 Object* obj = args[0];
5417 if (obj->IsSmi()) {
5418 return obj;
5419 }
5420 if (obj->IsHeapNumber()) {
5421 double value = HeapNumber::cast(obj)->value();
5422 int int_value = FastD2I(value);
5423 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
5424 return Smi::FromInt(int_value);
5425 }
5426 }
5427 return Heap::nan_value();
5428}
5429
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005430
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005431static MaybeObject* Runtime_AllocateHeapNumber(Arguments args) {
5432 NoHandleAllocation ha;
5433 ASSERT(args.length() == 0);
5434 return Heap::AllocateHeapNumber(0);
5435}
5436
5437
lrn@chromium.org303ada72010-10-27 09:33:13 +00005438static MaybeObject* Runtime_NumberAdd(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005439 NoHandleAllocation ha;
5440 ASSERT(args.length() == 2);
5441
5442 CONVERT_DOUBLE_CHECKED(x, args[0]);
5443 CONVERT_DOUBLE_CHECKED(y, args[1]);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00005444 return Heap::NumberFromDouble(x + y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005445}
5446
5447
lrn@chromium.org303ada72010-10-27 09:33:13 +00005448static MaybeObject* Runtime_NumberSub(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005449 NoHandleAllocation ha;
5450 ASSERT(args.length() == 2);
5451
5452 CONVERT_DOUBLE_CHECKED(x, args[0]);
5453 CONVERT_DOUBLE_CHECKED(y, args[1]);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00005454 return Heap::NumberFromDouble(x - y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005455}
5456
5457
lrn@chromium.org303ada72010-10-27 09:33:13 +00005458static MaybeObject* Runtime_NumberMul(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005459 NoHandleAllocation ha;
5460 ASSERT(args.length() == 2);
5461
5462 CONVERT_DOUBLE_CHECKED(x, args[0]);
5463 CONVERT_DOUBLE_CHECKED(y, args[1]);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00005464 return Heap::NumberFromDouble(x * y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005465}
5466
5467
lrn@chromium.org303ada72010-10-27 09:33:13 +00005468static MaybeObject* Runtime_NumberUnaryMinus(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005469 NoHandleAllocation ha;
5470 ASSERT(args.length() == 1);
5471
5472 CONVERT_DOUBLE_CHECKED(x, args[0]);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00005473 return Heap::NumberFromDouble(-x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005474}
5475
5476
lrn@chromium.org303ada72010-10-27 09:33:13 +00005477static MaybeObject* Runtime_NumberAlloc(Arguments args) {
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00005478 NoHandleAllocation ha;
5479 ASSERT(args.length() == 0);
5480
5481 return Heap::NumberFromDouble(9876543210.0);
5482}
5483
5484
lrn@chromium.org303ada72010-10-27 09:33:13 +00005485static MaybeObject* Runtime_NumberDiv(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005486 NoHandleAllocation ha;
5487 ASSERT(args.length() == 2);
5488
5489 CONVERT_DOUBLE_CHECKED(x, args[0]);
5490 CONVERT_DOUBLE_CHECKED(y, args[1]);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00005491 return Heap::NumberFromDouble(x / y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005492}
5493
5494
lrn@chromium.org303ada72010-10-27 09:33:13 +00005495static MaybeObject* Runtime_NumberMod(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005496 NoHandleAllocation ha;
5497 ASSERT(args.length() == 2);
5498
5499 CONVERT_DOUBLE_CHECKED(x, args[0]);
5500 CONVERT_DOUBLE_CHECKED(y, args[1]);
5501
ager@chromium.org3811b432009-10-28 14:53:37 +00005502 x = modulo(x, y);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00005503 // NumberFromDouble may return a Smi instead of a Number object
5504 return Heap::NumberFromDouble(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005505}
5506
5507
lrn@chromium.org303ada72010-10-27 09:33:13 +00005508static MaybeObject* Runtime_StringAdd(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005509 NoHandleAllocation ha;
5510 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005511 CONVERT_CHECKED(String, str1, args[0]);
5512 CONVERT_CHECKED(String, str2, args[1]);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00005513 Counters::string_add_runtime.Increment();
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00005514 return Heap::AllocateConsString(str1, str2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005515}
5516
5517
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005518template <typename sinkchar>
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005519static inline void StringBuilderConcatHelper(String* special,
5520 sinkchar* sink,
5521 FixedArray* fixed_array,
5522 int array_length) {
5523 int position = 0;
5524 for (int i = 0; i < array_length; i++) {
5525 Object* element = fixed_array->get(i);
5526 if (element->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005527 // Smi encoding of position and length.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005528 int encoded_slice = Smi::cast(element)->value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005529 int pos;
5530 int len;
5531 if (encoded_slice > 0) {
5532 // Position and length encoded in one smi.
5533 pos = StringBuilderSubstringPosition::decode(encoded_slice);
5534 len = StringBuilderSubstringLength::decode(encoded_slice);
5535 } else {
5536 // Position and length encoded in two smis.
5537 Object* obj = fixed_array->get(++i);
5538 ASSERT(obj->IsSmi());
5539 pos = Smi::cast(obj)->value();
5540 len = -encoded_slice;
5541 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00005542 String::WriteToFlat(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00005543 sink + position,
5544 pos,
5545 pos + len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005546 position += len;
5547 } else {
5548 String* string = String::cast(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005549 int element_length = string->length();
5550 String::WriteToFlat(string, sink + position, 0, element_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005551 position += element_length;
5552 }
5553 }
5554}
5555
5556
lrn@chromium.org303ada72010-10-27 09:33:13 +00005557static MaybeObject* Runtime_StringBuilderConcat(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005558 NoHandleAllocation ha;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005559 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005560 CONVERT_CHECKED(JSArray, array, args[0]);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005561 if (!args[1]->IsSmi()) {
5562 Top::context()->mark_out_of_memory();
5563 return Failure::OutOfMemoryException();
5564 }
5565 int array_length = Smi::cast(args[1])->value();
5566 CONVERT_CHECKED(String, special, args[2]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005567
5568 // This assumption is used by the slice encoding in one or two smis.
5569 ASSERT(Smi::kMaxValue >= String::kMaxLength);
5570
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005571 int special_length = special->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005572 if (!array->HasFastElements()) {
5573 return Top::Throw(Heap::illegal_argument_symbol());
5574 }
5575 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005576 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005577 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005578 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005579
5580 if (array_length == 0) {
5581 return Heap::empty_string();
5582 } else if (array_length == 1) {
5583 Object* first = fixed_array->get(0);
5584 if (first->IsString()) return first;
5585 }
5586
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005587 bool ascii = special->HasOnlyAsciiChars();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005588 int position = 0;
5589 for (int i = 0; i < array_length; i++) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005590 int increment = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005591 Object* elt = fixed_array->get(i);
5592 if (elt->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005593 // Smi encoding of position and length.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005594 int smi_value = Smi::cast(elt)->value();
5595 int pos;
5596 int len;
5597 if (smi_value > 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005598 // Position and length encoded in one smi.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005599 pos = StringBuilderSubstringPosition::decode(smi_value);
5600 len = StringBuilderSubstringLength::decode(smi_value);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005601 } else {
5602 // Position and length encoded in two smis.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005603 len = -smi_value;
5604 // Get the position and check that it is a positive smi.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005605 i++;
5606 if (i >= array_length) {
5607 return Top::Throw(Heap::illegal_argument_symbol());
5608 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005609 Object* next_smi = fixed_array->get(i);
5610 if (!next_smi->IsSmi()) {
5611 return Top::Throw(Heap::illegal_argument_symbol());
5612 }
5613 pos = Smi::cast(next_smi)->value();
5614 if (pos < 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005615 return Top::Throw(Heap::illegal_argument_symbol());
5616 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005617 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005618 ASSERT(pos >= 0);
5619 ASSERT(len >= 0);
5620 if (pos > special_length || len > special_length - pos) {
5621 return Top::Throw(Heap::illegal_argument_symbol());
5622 }
5623 increment = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005624 } else if (elt->IsString()) {
5625 String* element = String::cast(elt);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005626 int element_length = element->length();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005627 increment = element_length;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005628 if (ascii && !element->HasOnlyAsciiChars()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005629 ascii = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005630 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005631 } else {
5632 return Top::Throw(Heap::illegal_argument_symbol());
5633 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005634 if (increment > String::kMaxLength - position) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005635 Top::context()->mark_out_of_memory();
5636 return Failure::OutOfMemoryException();
5637 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005638 position += increment;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005639 }
5640
5641 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005642 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005643
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005644 if (ascii) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005645 { MaybeObject* maybe_object = Heap::AllocateRawAsciiString(length);
5646 if (!maybe_object->ToObject(&object)) return maybe_object;
5647 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005648 SeqAsciiString* answer = SeqAsciiString::cast(object);
5649 StringBuilderConcatHelper(special,
5650 answer->GetChars(),
5651 fixed_array,
5652 array_length);
5653 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005654 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005655 { MaybeObject* maybe_object = Heap::AllocateRawTwoByteString(length);
5656 if (!maybe_object->ToObject(&object)) return maybe_object;
5657 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005658 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
5659 StringBuilderConcatHelper(special,
5660 answer->GetChars(),
5661 fixed_array,
5662 array_length);
5663 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005664 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005665}
5666
5667
lrn@chromium.org303ada72010-10-27 09:33:13 +00005668static MaybeObject* Runtime_NumberOr(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005669 NoHandleAllocation ha;
5670 ASSERT(args.length() == 2);
5671
5672 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5673 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5674 return Heap::NumberFromInt32(x | y);
5675}
5676
5677
lrn@chromium.org303ada72010-10-27 09:33:13 +00005678static MaybeObject* Runtime_NumberAnd(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005679 NoHandleAllocation ha;
5680 ASSERT(args.length() == 2);
5681
5682 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5683 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5684 return Heap::NumberFromInt32(x & y);
5685}
5686
5687
lrn@chromium.org303ada72010-10-27 09:33:13 +00005688static MaybeObject* Runtime_NumberXor(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005689 NoHandleAllocation ha;
5690 ASSERT(args.length() == 2);
5691
5692 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5693 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5694 return Heap::NumberFromInt32(x ^ y);
5695}
5696
5697
lrn@chromium.org303ada72010-10-27 09:33:13 +00005698static MaybeObject* Runtime_NumberNot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005699 NoHandleAllocation ha;
5700 ASSERT(args.length() == 1);
5701
5702 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5703 return Heap::NumberFromInt32(~x);
5704}
5705
5706
lrn@chromium.org303ada72010-10-27 09:33:13 +00005707static MaybeObject* Runtime_NumberShl(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005708 NoHandleAllocation ha;
5709 ASSERT(args.length() == 2);
5710
5711 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5712 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5713 return Heap::NumberFromInt32(x << (y & 0x1f));
5714}
5715
5716
lrn@chromium.org303ada72010-10-27 09:33:13 +00005717static MaybeObject* Runtime_NumberShr(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005718 NoHandleAllocation ha;
5719 ASSERT(args.length() == 2);
5720
5721 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
5722 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5723 return Heap::NumberFromUint32(x >> (y & 0x1f));
5724}
5725
5726
lrn@chromium.org303ada72010-10-27 09:33:13 +00005727static MaybeObject* Runtime_NumberSar(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005728 NoHandleAllocation ha;
5729 ASSERT(args.length() == 2);
5730
5731 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5732 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5733 return Heap::NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
5734}
5735
5736
lrn@chromium.org303ada72010-10-27 09:33:13 +00005737static MaybeObject* Runtime_NumberEquals(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005738 NoHandleAllocation ha;
5739 ASSERT(args.length() == 2);
5740
5741 CONVERT_DOUBLE_CHECKED(x, args[0]);
5742 CONVERT_DOUBLE_CHECKED(y, args[1]);
5743 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
5744 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
5745 if (x == y) return Smi::FromInt(EQUAL);
5746 Object* result;
5747 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
5748 result = Smi::FromInt(EQUAL);
5749 } else {
5750 result = Smi::FromInt(NOT_EQUAL);
5751 }
5752 return result;
5753}
5754
5755
lrn@chromium.org303ada72010-10-27 09:33:13 +00005756static MaybeObject* Runtime_StringEquals(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005757 NoHandleAllocation ha;
5758 ASSERT(args.length() == 2);
5759
5760 CONVERT_CHECKED(String, x, args[0]);
5761 CONVERT_CHECKED(String, y, args[1]);
5762
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005763 bool not_equal = !x->Equals(y);
5764 // This is slightly convoluted because the value that signifies
5765 // equality is 0 and inequality is 1 so we have to negate the result
5766 // from String::Equals.
5767 ASSERT(not_equal == 0 || not_equal == 1);
5768 STATIC_CHECK(EQUAL == 0);
5769 STATIC_CHECK(NOT_EQUAL == 1);
5770 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005771}
5772
5773
lrn@chromium.org303ada72010-10-27 09:33:13 +00005774static MaybeObject* Runtime_NumberCompare(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005775 NoHandleAllocation ha;
5776 ASSERT(args.length() == 3);
5777
5778 CONVERT_DOUBLE_CHECKED(x, args[0]);
5779 CONVERT_DOUBLE_CHECKED(y, args[1]);
5780 if (isnan(x) || isnan(y)) return args[2];
5781 if (x == y) return Smi::FromInt(EQUAL);
5782 if (isless(x, y)) return Smi::FromInt(LESS);
5783 return Smi::FromInt(GREATER);
5784}
5785
5786
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005787// Compare two Smis as if they were converted to strings and then
5788// compared lexicographically.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005789static MaybeObject* Runtime_SmiLexicographicCompare(Arguments args) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005790 NoHandleAllocation ha;
5791 ASSERT(args.length() == 2);
5792
5793 // Arrays for the individual characters of the two Smis. Smis are
5794 // 31 bit integers and 10 decimal digits are therefore enough.
5795 static int x_elms[10];
5796 static int y_elms[10];
5797
5798 // Extract the integer values from the Smis.
5799 CONVERT_CHECKED(Smi, x, args[0]);
5800 CONVERT_CHECKED(Smi, y, args[1]);
5801 int x_value = x->value();
5802 int y_value = y->value();
5803
5804 // If the integers are equal so are the string representations.
5805 if (x_value == y_value) return Smi::FromInt(EQUAL);
5806
5807 // If one of the integers are zero the normal integer order is the
5808 // same as the lexicographic order of the string representations.
5809 if (x_value == 0 || y_value == 0) return Smi::FromInt(x_value - y_value);
5810
ager@chromium.org32912102009-01-16 10:38:43 +00005811 // If only one of the integers is negative the negative number is
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005812 // smallest because the char code of '-' is less than the char code
5813 // of any digit. Otherwise, we make both values positive.
5814 if (x_value < 0 || y_value < 0) {
5815 if (y_value >= 0) return Smi::FromInt(LESS);
5816 if (x_value >= 0) return Smi::FromInt(GREATER);
5817 x_value = -x_value;
5818 y_value = -y_value;
5819 }
5820
5821 // Convert the integers to arrays of their decimal digits.
5822 int x_index = 0;
5823 int y_index = 0;
5824 while (x_value > 0) {
5825 x_elms[x_index++] = x_value % 10;
5826 x_value /= 10;
5827 }
5828 while (y_value > 0) {
5829 y_elms[y_index++] = y_value % 10;
5830 y_value /= 10;
5831 }
5832
5833 // Loop through the arrays of decimal digits finding the first place
5834 // where they differ.
5835 while (--x_index >= 0 && --y_index >= 0) {
5836 int diff = x_elms[x_index] - y_elms[y_index];
5837 if (diff != 0) return Smi::FromInt(diff);
5838 }
5839
5840 // If one array is a suffix of the other array, the longest array is
5841 // the representation of the largest of the Smis in the
5842 // lexicographic ordering.
5843 return Smi::FromInt(x_index - y_index);
5844}
5845
5846
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005847static Object* StringInputBufferCompare(String* x, String* y) {
5848 static StringInputBuffer bufx;
5849 static StringInputBuffer bufy;
5850 bufx.Reset(x);
5851 bufy.Reset(y);
5852 while (bufx.has_more() && bufy.has_more()) {
5853 int d = bufx.GetNext() - bufy.GetNext();
5854 if (d < 0) return Smi::FromInt(LESS);
5855 else if (d > 0) return Smi::FromInt(GREATER);
5856 }
5857
5858 // x is (non-trivial) prefix of y:
5859 if (bufy.has_more()) return Smi::FromInt(LESS);
5860 // y is prefix of x:
5861 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
5862}
5863
5864
5865static Object* FlatStringCompare(String* x, String* y) {
5866 ASSERT(x->IsFlat());
5867 ASSERT(y->IsFlat());
5868 Object* equal_prefix_result = Smi::FromInt(EQUAL);
5869 int prefix_length = x->length();
5870 if (y->length() < prefix_length) {
5871 prefix_length = y->length();
5872 equal_prefix_result = Smi::FromInt(GREATER);
5873 } else if (y->length() > prefix_length) {
5874 equal_prefix_result = Smi::FromInt(LESS);
5875 }
5876 int r;
5877 if (x->IsAsciiRepresentation()) {
5878 Vector<const char> x_chars = x->ToAsciiVector();
5879 if (y->IsAsciiRepresentation()) {
5880 Vector<const char> y_chars = y->ToAsciiVector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005881 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005882 } else {
5883 Vector<const uc16> y_chars = y->ToUC16Vector();
5884 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
5885 }
5886 } else {
5887 Vector<const uc16> x_chars = x->ToUC16Vector();
5888 if (y->IsAsciiRepresentation()) {
5889 Vector<const char> y_chars = y->ToAsciiVector();
5890 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
5891 } else {
5892 Vector<const uc16> y_chars = y->ToUC16Vector();
5893 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
5894 }
5895 }
5896 Object* result;
5897 if (r == 0) {
5898 result = equal_prefix_result;
5899 } else {
5900 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
5901 }
5902 ASSERT(result == StringInputBufferCompare(x, y));
5903 return result;
5904}
5905
5906
lrn@chromium.org303ada72010-10-27 09:33:13 +00005907static MaybeObject* Runtime_StringCompare(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005908 NoHandleAllocation ha;
5909 ASSERT(args.length() == 2);
5910
5911 CONVERT_CHECKED(String, x, args[0]);
5912 CONVERT_CHECKED(String, y, args[1]);
5913
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005914 Counters::string_compare_runtime.Increment();
5915
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005916 // A few fast case tests before we flatten.
5917 if (x == y) return Smi::FromInt(EQUAL);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005918 if (y->length() == 0) {
5919 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005920 return Smi::FromInt(GREATER);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005921 } else if (x->length() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005922 return Smi::FromInt(LESS);
5923 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005924
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005925 int d = x->Get(0) - y->Get(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005926 if (d < 0) return Smi::FromInt(LESS);
5927 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005928
lrn@chromium.org303ada72010-10-27 09:33:13 +00005929 Object* obj;
5930 { MaybeObject* maybe_obj = Heap::PrepareForCompare(x);
5931 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5932 }
5933 { MaybeObject* maybe_obj = Heap::PrepareForCompare(y);
5934 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5935 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005936
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005937 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
5938 : StringInputBufferCompare(x, y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005939}
5940
5941
lrn@chromium.org303ada72010-10-27 09:33:13 +00005942static MaybeObject* Runtime_Math_acos(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005943 NoHandleAllocation ha;
5944 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005945 Counters::math_acos.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005946
5947 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005948 return TranscendentalCache::Get(TranscendentalCache::ACOS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005949}
5950
5951
lrn@chromium.org303ada72010-10-27 09:33:13 +00005952static MaybeObject* Runtime_Math_asin(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005953 NoHandleAllocation ha;
5954 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005955 Counters::math_asin.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005956
5957 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005958 return TranscendentalCache::Get(TranscendentalCache::ASIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005959}
5960
5961
lrn@chromium.org303ada72010-10-27 09:33:13 +00005962static MaybeObject* Runtime_Math_atan(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005963 NoHandleAllocation ha;
5964 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005965 Counters::math_atan.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005966
5967 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005968 return TranscendentalCache::Get(TranscendentalCache::ATAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005969}
5970
5971
lrn@chromium.org303ada72010-10-27 09:33:13 +00005972static MaybeObject* Runtime_Math_atan2(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005973 NoHandleAllocation ha;
5974 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005975 Counters::math_atan2.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005976
5977 CONVERT_DOUBLE_CHECKED(x, args[0]);
5978 CONVERT_DOUBLE_CHECKED(y, args[1]);
5979 double result;
5980 if (isinf(x) && isinf(y)) {
5981 // Make sure that the result in case of two infinite arguments
5982 // is a multiple of Pi / 4. The sign of the result is determined
5983 // by the first argument (x) and the sign of the second argument
5984 // determines the multiplier: one or three.
5985 static double kPiDividedBy4 = 0.78539816339744830962;
5986 int multiplier = (x < 0) ? -1 : 1;
5987 if (y < 0) multiplier *= 3;
5988 result = multiplier * kPiDividedBy4;
5989 } else {
5990 result = atan2(x, y);
5991 }
5992 return Heap::AllocateHeapNumber(result);
5993}
5994
5995
lrn@chromium.org303ada72010-10-27 09:33:13 +00005996static MaybeObject* Runtime_Math_ceil(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005997 NoHandleAllocation ha;
5998 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005999 Counters::math_ceil.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006000
6001 CONVERT_DOUBLE_CHECKED(x, args[0]);
6002 return Heap::NumberFromDouble(ceiling(x));
6003}
6004
6005
lrn@chromium.org303ada72010-10-27 09:33:13 +00006006static MaybeObject* Runtime_Math_cos(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006007 NoHandleAllocation ha;
6008 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006009 Counters::math_cos.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006010
6011 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006012 return TranscendentalCache::Get(TranscendentalCache::COS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006013}
6014
6015
lrn@chromium.org303ada72010-10-27 09:33:13 +00006016static MaybeObject* Runtime_Math_exp(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006017 NoHandleAllocation ha;
6018 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006019 Counters::math_exp.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006020
6021 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006022 return TranscendentalCache::Get(TranscendentalCache::EXP, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006023}
6024
6025
lrn@chromium.org303ada72010-10-27 09:33:13 +00006026static MaybeObject* Runtime_Math_floor(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006027 NoHandleAllocation ha;
6028 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006029 Counters::math_floor.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006030
6031 CONVERT_DOUBLE_CHECKED(x, args[0]);
6032 return Heap::NumberFromDouble(floor(x));
6033}
6034
6035
lrn@chromium.org303ada72010-10-27 09:33:13 +00006036static MaybeObject* Runtime_Math_log(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006037 NoHandleAllocation ha;
6038 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006039 Counters::math_log.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006040
6041 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006042 return TranscendentalCache::Get(TranscendentalCache::LOG, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006043}
6044
6045
lrn@chromium.org303ada72010-10-27 09:33:13 +00006046static MaybeObject* Runtime_Math_pow(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006047 NoHandleAllocation ha;
6048 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006049 Counters::math_pow.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006050
6051 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006052
6053 // If the second argument is a smi, it is much faster to call the
6054 // custom powi() function than the generic pow().
6055 if (args[1]->IsSmi()) {
6056 int y = Smi::cast(args[1])->value();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006057 return Heap::NumberFromDouble(power_double_int(x, y));
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006058 }
6059
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006060 CONVERT_DOUBLE_CHECKED(y, args[1]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006061 return Heap::AllocateHeapNumber(power_double_double(x, y));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006062}
6063
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006064// Fast version of Math.pow if we know that y is not an integer and
6065// y is not -0.5 or 0.5. Used as slowcase from codegen.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006066static MaybeObject* Runtime_Math_pow_cfunction(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006067 NoHandleAllocation ha;
6068 ASSERT(args.length() == 2);
6069 CONVERT_DOUBLE_CHECKED(x, args[0]);
6070 CONVERT_DOUBLE_CHECKED(y, args[1]);
6071 if (y == 0) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006072 return Smi::FromInt(1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006073 } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006074 return Heap::nan_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006075 } else {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006076 return Heap::AllocateHeapNumber(pow(x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006077 }
6078}
6079
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006080
lrn@chromium.org303ada72010-10-27 09:33:13 +00006081static MaybeObject* Runtime_RoundNumber(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006082 NoHandleAllocation ha;
6083 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006084 Counters::math_round.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006085
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006086 if (!args[0]->IsHeapNumber()) {
6087 // Must be smi. Return the argument unchanged for all the other types
6088 // to make fuzz-natives test happy.
6089 return args[0];
6090 }
6091
6092 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
6093
6094 double value = number->value();
6095 int exponent = number->get_exponent();
6096 int sign = number->get_sign();
6097
6098 // We compare with kSmiValueSize - 3 because (2^30 - 0.1) has exponent 29 and
6099 // should be rounded to 2^30, which is not smi.
6100 if (!sign && exponent <= kSmiValueSize - 3) {
6101 return Smi::FromInt(static_cast<int>(value + 0.5));
6102 }
6103
6104 // If the magnitude is big enough, there's no place for fraction part. If we
6105 // try to add 0.5 to this number, 1.0 will be added instead.
6106 if (exponent >= 52) {
6107 return number;
6108 }
6109
6110 if (sign && value >= -0.5) return Heap::minus_zero_value();
6111
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006112 // Do not call NumberFromDouble() to avoid extra checks.
6113 return Heap::AllocateHeapNumber(floor(value + 0.5));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006114}
6115
6116
lrn@chromium.org303ada72010-10-27 09:33:13 +00006117static MaybeObject* Runtime_Math_sin(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006118 NoHandleAllocation ha;
6119 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006120 Counters::math_sin.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006121
6122 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006123 return TranscendentalCache::Get(TranscendentalCache::SIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006124}
6125
6126
lrn@chromium.org303ada72010-10-27 09:33:13 +00006127static MaybeObject* Runtime_Math_sqrt(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006128 NoHandleAllocation ha;
6129 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006130 Counters::math_sqrt.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006131
6132 CONVERT_DOUBLE_CHECKED(x, args[0]);
6133 return Heap::AllocateHeapNumber(sqrt(x));
6134}
6135
6136
lrn@chromium.org303ada72010-10-27 09:33:13 +00006137static MaybeObject* Runtime_Math_tan(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006138 NoHandleAllocation ha;
6139 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006140 Counters::math_tan.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006141
6142 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006143 return TranscendentalCache::Get(TranscendentalCache::TAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006144}
6145
6146
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006147static int MakeDay(int year, int month, int day) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006148 static const int day_from_month[] = {0, 31, 59, 90, 120, 151,
6149 181, 212, 243, 273, 304, 334};
6150 static const int day_from_month_leap[] = {0, 31, 60, 91, 121, 152,
6151 182, 213, 244, 274, 305, 335};
6152
6153 year += month / 12;
6154 month %= 12;
6155 if (month < 0) {
6156 year--;
6157 month += 12;
6158 }
6159
6160 ASSERT(month >= 0);
6161 ASSERT(month < 12);
6162
6163 // year_delta is an arbitrary number such that:
6164 // a) year_delta = -1 (mod 400)
6165 // b) year + year_delta > 0 for years in the range defined by
6166 // ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of
6167 // Jan 1 1970. This is required so that we don't run into integer
6168 // division of negative numbers.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006169 // c) there shouldn't be an overflow for 32-bit integers in the following
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006170 // operations.
6171 static const int year_delta = 399999;
6172 static const int base_day = 365 * (1970 + year_delta) +
6173 (1970 + year_delta) / 4 -
6174 (1970 + year_delta) / 100 +
6175 (1970 + year_delta) / 400;
6176
6177 int year1 = year + year_delta;
6178 int day_from_year = 365 * year1 +
6179 year1 / 4 -
6180 year1 / 100 +
6181 year1 / 400 -
6182 base_day;
6183
6184 if (year % 4 || (year % 100 == 0 && year % 400 != 0)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006185 return day_from_year + day_from_month[month] + day - 1;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006186 }
6187
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006188 return day_from_year + day_from_month_leap[month] + day - 1;
6189}
6190
6191
lrn@chromium.org303ada72010-10-27 09:33:13 +00006192static MaybeObject* Runtime_DateMakeDay(Arguments args) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006193 NoHandleAllocation ha;
6194 ASSERT(args.length() == 3);
6195
6196 CONVERT_SMI_CHECKED(year, args[0]);
6197 CONVERT_SMI_CHECKED(month, args[1]);
6198 CONVERT_SMI_CHECKED(date, args[2]);
6199
6200 return Smi::FromInt(MakeDay(year, month, date));
6201}
6202
6203
6204static const int kDays4Years[] = {0, 365, 2 * 365, 3 * 365 + 1};
6205static const int kDaysIn4Years = 4 * 365 + 1;
6206static const int kDaysIn100Years = 25 * kDaysIn4Years - 1;
6207static const int kDaysIn400Years = 4 * kDaysIn100Years + 1;
6208static const int kDays1970to2000 = 30 * 365 + 7;
6209static const int kDaysOffset = 1000 * kDaysIn400Years + 5 * kDaysIn400Years -
6210 kDays1970to2000;
6211static const int kYearsOffset = 400000;
6212
6213static const char kDayInYear[] = {
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,
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,
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, 31,
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 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6235 22, 23, 24, 25, 26, 27, 28, 29, 30,
6236 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6237 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6238
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,
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,
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, 31,
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 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6260 22, 23, 24, 25, 26, 27, 28, 29, 30,
6261 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6262 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6263
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,
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,
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, 31,
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 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6285 22, 23, 24, 25, 26, 27, 28, 29, 30,
6286 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6287 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6288
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,
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,
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, 31,
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 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6310 22, 23, 24, 25, 26, 27, 28, 29, 30,
6311 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6312 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
6313
6314static const char kMonthInYear[] = {
6315 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,
6316 0, 0, 0, 0, 0, 0,
6317 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,
6318 1, 1, 1,
6319 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,
6320 2, 2, 2, 2, 2, 2,
6321 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,
6322 3, 3, 3, 3, 3,
6323 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,
6324 4, 4, 4, 4, 4, 4,
6325 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,
6326 5, 5, 5, 5, 5,
6327 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,
6328 6, 6, 6, 6, 6, 6,
6329 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,
6330 7, 7, 7, 7, 7, 7,
6331 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,
6332 8, 8, 8, 8, 8,
6333 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,
6334 9, 9, 9, 9, 9, 9,
6335 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6336 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6337 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6338 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6339
6340 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,
6341 0, 0, 0, 0, 0, 0,
6342 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,
6343 1, 1, 1,
6344 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,
6345 2, 2, 2, 2, 2, 2,
6346 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,
6347 3, 3, 3, 3, 3,
6348 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,
6349 4, 4, 4, 4, 4, 4,
6350 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,
6351 5, 5, 5, 5, 5,
6352 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,
6353 6, 6, 6, 6, 6, 6,
6354 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,
6355 7, 7, 7, 7, 7, 7,
6356 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,
6357 8, 8, 8, 8, 8,
6358 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,
6359 9, 9, 9, 9, 9, 9,
6360 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6361 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6362 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6363 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6364
6365 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,
6366 0, 0, 0, 0, 0, 0,
6367 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,
6368 1, 1, 1, 1,
6369 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,
6370 2, 2, 2, 2, 2, 2,
6371 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,
6372 3, 3, 3, 3, 3,
6373 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,
6374 4, 4, 4, 4, 4, 4,
6375 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,
6376 5, 5, 5, 5, 5,
6377 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,
6378 6, 6, 6, 6, 6, 6,
6379 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,
6380 7, 7, 7, 7, 7, 7,
6381 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,
6382 8, 8, 8, 8, 8,
6383 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,
6384 9, 9, 9, 9, 9, 9,
6385 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6386 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6387 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6388 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6389
6390 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,
6391 0, 0, 0, 0, 0, 0,
6392 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,
6393 1, 1, 1,
6394 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,
6395 2, 2, 2, 2, 2, 2,
6396 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,
6397 3, 3, 3, 3, 3,
6398 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,
6399 4, 4, 4, 4, 4, 4,
6400 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,
6401 5, 5, 5, 5, 5,
6402 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,
6403 6, 6, 6, 6, 6, 6,
6404 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,
6405 7, 7, 7, 7, 7, 7,
6406 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,
6407 8, 8, 8, 8, 8,
6408 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,
6409 9, 9, 9, 9, 9, 9,
6410 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6411 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6412 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6413 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11};
6414
6415
6416// This function works for dates from 1970 to 2099.
6417static inline void DateYMDFromTimeAfter1970(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006418 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006419#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00006420 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006421#endif
6422
6423 year = 1970 + (4 * date + 2) / kDaysIn4Years;
6424 date %= kDaysIn4Years;
6425
6426 month = kMonthInYear[date];
6427 day = kDayInYear[date];
6428
6429 ASSERT(MakeDay(year, month, day) == save_date);
6430}
6431
6432
6433static inline void DateYMDFromTimeSlow(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006434 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006435#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00006436 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006437#endif
6438
6439 date += kDaysOffset;
6440 year = 400 * (date / kDaysIn400Years) - kYearsOffset;
6441 date %= kDaysIn400Years;
6442
6443 ASSERT(MakeDay(year, 0, 1) + date == save_date);
6444
6445 date--;
6446 int yd1 = date / kDaysIn100Years;
6447 date %= kDaysIn100Years;
6448 year += 100 * yd1;
6449
6450 date++;
6451 int yd2 = date / kDaysIn4Years;
6452 date %= kDaysIn4Years;
6453 year += 4 * yd2;
6454
6455 date--;
6456 int yd3 = date / 365;
6457 date %= 365;
6458 year += yd3;
6459
6460 bool is_leap = (!yd1 || yd2) && !yd3;
6461
6462 ASSERT(date >= -1);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006463 ASSERT(is_leap || (date >= 0));
6464 ASSERT((date < 365) || (is_leap && (date < 366)));
6465 ASSERT(is_leap == ((year % 4 == 0) && (year % 100 || (year % 400 == 0))));
6466 ASSERT(is_leap || ((MakeDay(year, 0, 1) + date) == save_date));
6467 ASSERT(!is_leap || ((MakeDay(year, 0, 1) + date + 1) == save_date));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006468
6469 if (is_leap) {
6470 day = kDayInYear[2*365 + 1 + date];
6471 month = kMonthInYear[2*365 + 1 + date];
6472 } else {
6473 day = kDayInYear[date];
6474 month = kMonthInYear[date];
6475 }
6476
6477 ASSERT(MakeDay(year, month, day) == save_date);
6478}
6479
6480
6481static inline void DateYMDFromTime(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006482 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006483 if (date >= 0 && date < 32 * kDaysIn4Years) {
6484 DateYMDFromTimeAfter1970(date, year, month, day);
6485 } else {
6486 DateYMDFromTimeSlow(date, year, month, day);
6487 }
6488}
6489
6490
lrn@chromium.org303ada72010-10-27 09:33:13 +00006491static MaybeObject* Runtime_DateYMDFromTime(Arguments args) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006492 NoHandleAllocation ha;
6493 ASSERT(args.length() == 2);
6494
6495 CONVERT_DOUBLE_CHECKED(t, args[0]);
6496 CONVERT_CHECKED(JSArray, res_array, args[1]);
6497
6498 int year, month, day;
6499 DateYMDFromTime(static_cast<int>(floor(t / 86400000)), year, month, day);
6500
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00006501 RUNTIME_ASSERT(res_array->elements()->map() == Heap::fixed_array_map());
6502 FixedArray* elms = FixedArray::cast(res_array->elements());
6503 RUNTIME_ASSERT(elms->length() == 3);
6504
6505 elms->set(0, Smi::FromInt(year));
6506 elms->set(1, Smi::FromInt(month));
6507 elms->set(2, Smi::FromInt(day));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006508
6509 return Heap::undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006510}
6511
6512
lrn@chromium.org303ada72010-10-27 09:33:13 +00006513static MaybeObject* Runtime_NewArgumentsFast(Arguments args) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00006514 NoHandleAllocation ha;
6515 ASSERT(args.length() == 3);
6516
6517 JSFunction* callee = JSFunction::cast(args[0]);
6518 Object** parameters = reinterpret_cast<Object**>(args[1]);
6519 const int length = Smi::cast(args[2])->value();
6520
lrn@chromium.org303ada72010-10-27 09:33:13 +00006521 Object* result;
6522 { MaybeObject* maybe_result = Heap::AllocateArgumentsObject(callee, length);
6523 if (!maybe_result->ToObject(&result)) return maybe_result;
6524 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006525 // Allocate the elements if needed.
6526 if (length > 0) {
6527 // Allocate the fixed array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006528 Object* obj;
6529 { MaybeObject* maybe_obj = Heap::AllocateRawFixedArray(length);
6530 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6531 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006532
6533 AssertNoAllocation no_gc;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006534 FixedArray* array = reinterpret_cast<FixedArray*>(obj);
6535 array->set_map(Heap::fixed_array_map());
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006536 array->set_length(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006537
6538 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006539 for (int i = 0; i < length; i++) {
6540 array->set(i, *--parameters, mode);
6541 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006542 JSObject::cast(result)->set_elements(FixedArray::cast(obj));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00006543 }
6544 return result;
6545}
6546
6547
lrn@chromium.org303ada72010-10-27 09:33:13 +00006548static MaybeObject* Runtime_NewClosure(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006549 HandleScope scope;
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00006550 ASSERT(args.length() == 3);
ager@chromium.org3811b432009-10-28 14:53:37 +00006551 CONVERT_ARG_CHECKED(Context, context, 0);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00006552 CONVERT_ARG_CHECKED(SharedFunctionInfo, shared, 1);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00006553 CONVERT_BOOLEAN_CHECKED(pretenure, args[2]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006554
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00006555 // Allocate global closures in old space and allocate local closures
6556 // in new space. Additionally pretenure closures that are assigned
6557 // directly to properties.
6558 pretenure = pretenure || (context->global_context() == *context);
6559 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006560 Handle<JSFunction> result =
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00006561 Factory::NewFunctionFromSharedFunctionInfo(shared,
6562 context,
6563 pretenure_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006564 return *result;
6565}
6566
lrn@chromium.org303ada72010-10-27 09:33:13 +00006567static MaybeObject* Runtime_NewObjectFromBound(Arguments args) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006568 HandleScope scope;
6569 ASSERT(args.length() == 2);
6570 CONVERT_ARG_CHECKED(JSFunction, function, 0);
6571 CONVERT_ARG_CHECKED(JSArray, params, 1);
6572
whesse@chromium.orge90029b2010-08-02 11:52:17 +00006573 RUNTIME_ASSERT(params->HasFastElements());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006574 FixedArray* fixed = FixedArray::cast(params->elements());
6575
whesse@chromium.orge90029b2010-08-02 11:52:17 +00006576 int fixed_length = Smi::cast(params->length())->value();
6577 SmartPointer<Object**> param_data(NewArray<Object**>(fixed_length));
6578 for (int i = 0; i < fixed_length; i++) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006579 Handle<Object> val = Handle<Object>(fixed->get(i));
6580 param_data[i] = val.location();
6581 }
6582
whesse@chromium.orge90029b2010-08-02 11:52:17 +00006583 bool exception = false;
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006584 Handle<Object> result = Execution::New(
whesse@chromium.orge90029b2010-08-02 11:52:17 +00006585 function, fixed_length, *param_data, &exception);
6586 if (exception) {
6587 return Failure::Exception();
6588 }
6589 ASSERT(!result.is_null());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006590 return *result;
6591}
6592
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006593
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006594static void TrySettingInlineConstructStub(Handle<JSFunction> function) {
ager@chromium.org5c838252010-02-19 08:53:10 +00006595 Handle<Object> prototype = Factory::null_value();
6596 if (function->has_instance_prototype()) {
6597 prototype = Handle<Object>(function->instance_prototype());
6598 }
6599 if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006600 ConstructStubCompiler compiler;
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006601 MaybeObject* code = compiler.CompileConstructStub(*function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006602 if (!code->IsFailure()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00006603 function->shared()->set_construct_stub(
6604 Code::cast(code->ToObjectUnchecked()));
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006605 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006606 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006607}
6608
6609
lrn@chromium.org303ada72010-10-27 09:33:13 +00006610static MaybeObject* Runtime_NewObject(Arguments args) {
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006611 HandleScope scope;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006612 ASSERT(args.length() == 1);
6613
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006614 Handle<Object> constructor = args.at<Object>(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006615
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006616 // If the constructor isn't a proper function we throw a type error.
6617 if (!constructor->IsJSFunction()) {
6618 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
6619 Handle<Object> type_error =
6620 Factory::NewTypeError("not_constructor", arguments);
6621 return Top::Throw(*type_error);
6622 }
6623
6624 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006625
6626 // If function should not have prototype, construction is not allowed. In this
6627 // case generated code bailouts here, since function has no initial_map.
6628 if (!function->should_have_prototype()) {
6629 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
6630 Handle<Object> type_error =
6631 Factory::NewTypeError("not_constructor", arguments);
6632 return Top::Throw(*type_error);
6633 }
6634
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006635#ifdef ENABLE_DEBUGGER_SUPPORT
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006636 // Handle stepping into constructors if step into is active.
6637 if (Debug::StepInActive()) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006638 Debug::HandleStepIn(function, Handle<Object>::null(), 0, true);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006639 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006640#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006641
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006642 if (function->has_initial_map()) {
6643 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006644 // The 'Function' function ignores the receiver object when
6645 // called using 'new' and creates a new JSFunction object that
6646 // is returned. The receiver object is only used for error
6647 // reporting if an error occurs when constructing the new
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006648 // JSFunction. Factory::NewJSObject() should not be used to
6649 // allocate JSFunctions since it does not properly initialize
6650 // the shared part of the function. Since the receiver is
6651 // ignored anyway, we use the global object as the receiver
6652 // instead of a new JSFunction object. This way, errors are
6653 // reported the same way whether or not 'Function' is called
6654 // using 'new'.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006655 return Top::context()->global();
6656 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006657 }
6658
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006659 // The function should be compiled for the optimization hints to be
6660 // available. We cannot use EnsureCompiled because that forces a
6661 // compilation through the shared function info which makes it
6662 // impossible for us to optimize.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006663 Handle<SharedFunctionInfo> shared(function->shared());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006664 if (!function->is_compiled()) CompileLazy(function, CLEAR_EXCEPTION);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006665
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006666 if (!function->has_initial_map() &&
6667 shared->IsInobjectSlackTrackingInProgress()) {
6668 // The tracking is already in progress for another function. We can only
6669 // track one initial_map at a time, so we force the completion before the
6670 // function is called as a constructor for the first time.
6671 shared->CompleteInobjectSlackTracking();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006672 }
6673
6674 bool first_allocation = !shared->live_objects_may_exist();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006675 Handle<JSObject> result = Factory::NewJSObject(function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006676 // Delay setting the stub if inobject slack tracking is in progress.
6677 if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) {
6678 TrySettingInlineConstructStub(function);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006679 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006680
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00006681 Counters::constructed_objects.Increment();
6682 Counters::constructed_objects_runtime.Increment();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006683
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006684 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006685}
6686
6687
lrn@chromium.org303ada72010-10-27 09:33:13 +00006688static MaybeObject* Runtime_FinalizeInstanceSize(Arguments args) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006689 HandleScope scope;
6690 ASSERT(args.length() == 1);
6691
6692 CONVERT_ARG_CHECKED(JSFunction, function, 0);
6693 function->shared()->CompleteInobjectSlackTracking();
6694 TrySettingInlineConstructStub(function);
6695
6696 return Heap::undefined_value();
6697}
6698
6699
lrn@chromium.org303ada72010-10-27 09:33:13 +00006700static MaybeObject* Runtime_LazyCompile(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006701 HandleScope scope;
6702 ASSERT(args.length() == 1);
6703
6704 Handle<JSFunction> function = args.at<JSFunction>(0);
6705#ifdef DEBUG
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00006706 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006707 PrintF("[lazy: ");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006708 function->PrintName();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006709 PrintF("]\n");
6710 }
6711#endif
6712
kasperl@chromium.org71affb52009-05-26 05:44:31 +00006713 // Compile the target function. Here we compile using CompileLazyInLoop in
6714 // order to get the optimized version. This helps code like delta-blue
6715 // that calls performance-critical routines through constructors. A
6716 // constructor call doesn't use a CallIC, it uses a LoadIC followed by a
6717 // direct call. Since the in-loop tracking takes place through CallICs
6718 // this means that things called through constructors are never known to
6719 // be in loops. We compile them as if they are in loops here just in case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006720 ASSERT(!function->is_compiled());
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00006721 if (!CompileLazyInLoop(function, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006722 return Failure::Exception();
6723 }
6724
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006725 // All done. Return the compiled code.
6726 ASSERT(function->is_compiled());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006727 return function->code();
6728}
6729
6730
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006731static MaybeObject* Runtime_LazyRecompile(Arguments args) {
6732 HandleScope scope;
6733 ASSERT(args.length() == 1);
6734 Handle<JSFunction> function = args.at<JSFunction>(0);
6735 // If the function is not optimizable or debugger is active continue using the
6736 // code from the full compiler.
6737 if (!function->shared()->code()->optimizable() ||
6738 Debug::has_break_points()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00006739 if (FLAG_trace_opt) {
6740 PrintF("[failed to optimize ");
6741 function->PrintName();
6742 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n",
6743 function->shared()->code()->optimizable() ? "T" : "F",
6744 Debug::has_break_points() ? "T" : "F");
6745 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006746 function->ReplaceCode(function->shared()->code());
6747 return function->code();
6748 }
6749 if (CompileOptimized(function, AstNode::kNoNumber)) {
6750 return function->code();
6751 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00006752 if (FLAG_trace_opt) {
6753 PrintF("[failed to optimize ");
6754 function->PrintName();
6755 PrintF(": optimized compilation failed]\n");
6756 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006757 function->ReplaceCode(function->shared()->code());
6758 return Failure::Exception();
6759}
6760
6761
6762static MaybeObject* Runtime_NotifyDeoptimized(Arguments args) {
6763 HandleScope scope;
6764 ASSERT(args.length() == 1);
6765 RUNTIME_ASSERT(args[0]->IsSmi());
6766 Deoptimizer::BailoutType type =
6767 static_cast<Deoptimizer::BailoutType>(Smi::cast(args[0])->value());
6768 Deoptimizer* deoptimizer = Deoptimizer::Grab();
6769 ASSERT(Heap::IsAllocationAllowed());
6770 int frames = deoptimizer->output_count();
6771
6772 JavaScriptFrameIterator it;
6773 JavaScriptFrame* frame = NULL;
6774 for (int i = 0; i < frames; i++) {
6775 if (i != 0) it.Advance();
6776 frame = it.frame();
6777 deoptimizer->InsertHeapNumberValues(frames - i - 1, frame);
6778 }
6779 delete deoptimizer;
6780
6781 RUNTIME_ASSERT(frame->function()->IsJSFunction());
6782 Handle<JSFunction> function(JSFunction::cast(frame->function()));
6783 Handle<Object> arguments;
6784 for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00006785 if (frame->GetExpression(i) == Heap::arguments_marker()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006786 if (arguments.is_null()) {
6787 // FunctionGetArguments can't throw an exception, so cast away the
6788 // doubt with an assert.
6789 arguments = Handle<Object>(
6790 Accessors::FunctionGetArguments(*function,
6791 NULL)->ToObjectUnchecked());
6792 ASSERT(*arguments != Heap::null_value());
6793 ASSERT(*arguments != Heap::undefined_value());
6794 }
6795 frame->SetExpression(i, *arguments);
6796 }
6797 }
6798
6799 CompilationCache::MarkForLazyOptimizing(function);
6800 if (type == Deoptimizer::EAGER) {
6801 RUNTIME_ASSERT(function->IsOptimized());
6802 } else {
6803 RUNTIME_ASSERT(!function->IsOptimized());
6804 }
6805
6806 // Avoid doing too much work when running with --always-opt and keep
6807 // the optimized code around.
6808 if (FLAG_always_opt || type == Deoptimizer::LAZY) {
6809 return Heap::undefined_value();
6810 }
6811
6812 // Count the number of optimized activations of the function.
6813 int activations = 0;
6814 while (!it.done()) {
6815 JavaScriptFrame* frame = it.frame();
6816 if (frame->is_optimized() && frame->function() == *function) {
6817 activations++;
6818 }
6819 it.Advance();
6820 }
6821
6822 // TODO(kasperl): For now, we cannot support removing the optimized
6823 // code when we have recursive invocations of the same function.
6824 if (activations == 0) {
6825 if (FLAG_trace_deopt) {
6826 PrintF("[removing optimized code for: ");
6827 function->PrintName();
6828 PrintF("]\n");
6829 }
6830 function->ReplaceCode(function->shared()->code());
6831 }
6832 return Heap::undefined_value();
6833}
6834
6835
6836static MaybeObject* Runtime_NotifyOSR(Arguments args) {
6837 Deoptimizer* deoptimizer = Deoptimizer::Grab();
6838 delete deoptimizer;
6839 return Heap::undefined_value();
6840}
6841
6842
6843static MaybeObject* Runtime_DeoptimizeFunction(Arguments args) {
6844 HandleScope scope;
6845 ASSERT(args.length() == 1);
6846 CONVERT_ARG_CHECKED(JSFunction, function, 0);
6847 if (!function->IsOptimized()) return Heap::undefined_value();
6848
6849 Deoptimizer::DeoptimizeFunction(*function);
6850
6851 return Heap::undefined_value();
6852}
6853
6854
6855static MaybeObject* Runtime_CompileForOnStackReplacement(Arguments args) {
6856 HandleScope scope;
6857 ASSERT(args.length() == 1);
6858 CONVERT_ARG_CHECKED(JSFunction, function, 0);
6859
6860 // We're not prepared to handle a function with arguments object.
6861 ASSERT(!function->shared()->scope_info()->HasArgumentsShadow());
6862
6863 // We have hit a back edge in an unoptimized frame for a function that was
6864 // selected for on-stack replacement. Find the unoptimized code object.
6865 Handle<Code> unoptimized(function->shared()->code());
6866 // Keep track of whether we've succeeded in optimizing.
6867 bool succeeded = unoptimized->optimizable();
6868 if (succeeded) {
6869 // If we are trying to do OSR when there are already optimized
6870 // activations of the function, it means (a) the function is directly or
6871 // indirectly recursive and (b) an optimized invocation has been
6872 // deoptimized so that we are currently in an unoptimized activation.
6873 // Check for optimized activations of this function.
6874 JavaScriptFrameIterator it;
6875 while (succeeded && !it.done()) {
6876 JavaScriptFrame* frame = it.frame();
6877 succeeded = !frame->is_optimized() || frame->function() != *function;
6878 it.Advance();
6879 }
6880 }
6881
6882 int ast_id = AstNode::kNoNumber;
6883 if (succeeded) {
6884 // The top JS function is this one, the PC is somewhere in the
6885 // unoptimized code.
6886 JavaScriptFrameIterator it;
6887 JavaScriptFrame* frame = it.frame();
6888 ASSERT(frame->function() == *function);
6889 ASSERT(frame->code() == *unoptimized);
6890 ASSERT(unoptimized->contains(frame->pc()));
6891
6892 // Use linear search of the unoptimized code's stack check table to find
6893 // the AST id matching the PC.
6894 Address start = unoptimized->instruction_start();
6895 unsigned target_pc_offset = static_cast<unsigned>(frame->pc() - start);
6896 Address table_cursor = start + unoptimized->stack_check_table_start();
6897 uint32_t table_length = Memory::uint32_at(table_cursor);
6898 table_cursor += kIntSize;
6899 for (unsigned i = 0; i < table_length; ++i) {
6900 // Table entries are (AST id, pc offset) pairs.
6901 uint32_t pc_offset = Memory::uint32_at(table_cursor + kIntSize);
6902 if (pc_offset == target_pc_offset) {
6903 ast_id = static_cast<int>(Memory::uint32_at(table_cursor));
6904 break;
6905 }
6906 table_cursor += 2 * kIntSize;
6907 }
6908 ASSERT(ast_id != AstNode::kNoNumber);
6909 if (FLAG_trace_osr) {
6910 PrintF("[replacing on-stack at AST id %d in ", ast_id);
6911 function->PrintName();
6912 PrintF("]\n");
6913 }
6914
6915 // Try to compile the optimized code. A true return value from
6916 // CompileOptimized means that compilation succeeded, not necessarily
6917 // that optimization succeeded.
6918 if (CompileOptimized(function, ast_id) && function->IsOptimized()) {
6919 DeoptimizationInputData* data = DeoptimizationInputData::cast(
6920 function->code()->deoptimization_data());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006921 if (data->OsrPcOffset()->value() >= 0) {
6922 if (FLAG_trace_osr) {
6923 PrintF("[on-stack replacement offset %d in optimized code]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006924 data->OsrPcOffset()->value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006925 }
6926 ASSERT(data->OsrAstId()->value() == ast_id);
6927 } else {
6928 // We may never generate the desired OSR entry if we emit an
6929 // early deoptimize.
6930 succeeded = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006931 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006932 } else {
6933 succeeded = false;
6934 }
6935 }
6936
6937 // Revert to the original stack checks in the original unoptimized code.
6938 if (FLAG_trace_osr) {
6939 PrintF("[restoring original stack checks in ");
6940 function->PrintName();
6941 PrintF("]\n");
6942 }
6943 StackCheckStub check_stub;
6944 Handle<Code> check_code = check_stub.GetCode();
6945 Handle<Code> replacement_code(
6946 Builtins::builtin(Builtins::OnStackReplacement));
6947 // Iterate the unoptimized code and revert all the patched stack checks.
6948 for (RelocIterator it(*unoptimized, RelocInfo::kCodeTargetMask);
6949 !it.done();
6950 it.next()) {
6951 RelocInfo* rinfo = it.rinfo();
6952 if (rinfo->target_address() == replacement_code->entry()) {
6953 Deoptimizer::RevertStackCheckCode(rinfo, *check_code);
6954 }
6955 }
6956
6957 // Allow OSR only at nesting level zero again.
6958 unoptimized->set_allow_osr_at_loop_nesting_level(0);
6959
6960 // If the optimization attempt succeeded, return the AST id tagged as a
6961 // smi. This tells the builtin that we need to translate the unoptimized
6962 // frame to an optimized one.
6963 if (succeeded) {
6964 ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
6965 return Smi::FromInt(ast_id);
6966 } else {
6967 return Smi::FromInt(-1);
6968 }
6969}
6970
6971
lrn@chromium.org303ada72010-10-27 09:33:13 +00006972static MaybeObject* Runtime_GetFunctionDelegate(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006973 HandleScope scope;
6974 ASSERT(args.length() == 1);
6975 RUNTIME_ASSERT(!args[0]->IsJSFunction());
6976 return *Execution::GetFunctionDelegate(args.at<Object>(0));
6977}
6978
6979
lrn@chromium.org303ada72010-10-27 09:33:13 +00006980static MaybeObject* Runtime_GetConstructorDelegate(Arguments args) {
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00006981 HandleScope scope;
6982 ASSERT(args.length() == 1);
6983 RUNTIME_ASSERT(!args[0]->IsJSFunction());
6984 return *Execution::GetConstructorDelegate(args.at<Object>(0));
6985}
6986
6987
lrn@chromium.org303ada72010-10-27 09:33:13 +00006988static MaybeObject* Runtime_NewContext(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006989 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00006990 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006991
kasper.lund7276f142008-07-30 08:49:36 +00006992 CONVERT_CHECKED(JSFunction, function, args[0]);
ager@chromium.orgb5737492010-07-15 09:29:43 +00006993 int length = function->shared()->scope_info()->NumberOfContextSlots();
lrn@chromium.org303ada72010-10-27 09:33:13 +00006994 Object* result;
6995 { MaybeObject* maybe_result = Heap::AllocateFunctionContext(length, function);
6996 if (!maybe_result->ToObject(&result)) return maybe_result;
6997 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006998
6999 Top::set_context(Context::cast(result));
7000
kasper.lund7276f142008-07-30 08:49:36 +00007001 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007002}
7003
lrn@chromium.org303ada72010-10-27 09:33:13 +00007004
7005MUST_USE_RESULT static MaybeObject* PushContextHelper(Object* object,
7006 bool is_catch_context) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007007 // Convert the object to a proper JavaScript object.
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007008 Object* js_object = object;
7009 if (!js_object->IsJSObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007010 MaybeObject* maybe_js_object = js_object->ToObject();
7011 if (!maybe_js_object->ToObject(&js_object)) {
7012 if (!Failure::cast(maybe_js_object)->IsInternalError()) {
7013 return maybe_js_object;
7014 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007015 HandleScope scope;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007016 Handle<Object> handle(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007017 Handle<Object> result =
7018 Factory::NewTypeError("with_expression", HandleVector(&handle, 1));
7019 return Top::Throw(*result);
7020 }
7021 }
7022
lrn@chromium.org303ada72010-10-27 09:33:13 +00007023 Object* result;
7024 { MaybeObject* maybe_result =
7025 Heap::AllocateWithContext(Top::context(),
7026 JSObject::cast(js_object),
7027 is_catch_context);
7028 if (!maybe_result->ToObject(&result)) return maybe_result;
7029 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007030
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007031 Context* context = Context::cast(result);
7032 Top::set_context(context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007033
kasper.lund7276f142008-07-30 08:49:36 +00007034 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007035}
7036
7037
lrn@chromium.org303ada72010-10-27 09:33:13 +00007038static MaybeObject* Runtime_PushContext(Arguments args) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007039 NoHandleAllocation ha;
7040 ASSERT(args.length() == 1);
7041 return PushContextHelper(args[0], false);
7042}
7043
7044
lrn@chromium.org303ada72010-10-27 09:33:13 +00007045static MaybeObject* Runtime_PushCatchContext(Arguments args) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007046 NoHandleAllocation ha;
7047 ASSERT(args.length() == 1);
7048 return PushContextHelper(args[0], true);
7049}
7050
7051
lrn@chromium.org303ada72010-10-27 09:33:13 +00007052static MaybeObject* Runtime_LookupContext(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007053 HandleScope scope;
7054 ASSERT(args.length() == 2);
7055
7056 CONVERT_ARG_CHECKED(Context, context, 0);
7057 CONVERT_ARG_CHECKED(String, name, 1);
7058
7059 int index;
7060 PropertyAttributes attributes;
7061 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007062 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007063 context->Lookup(name, flags, &index, &attributes);
7064
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007065 if (index < 0 && !holder.is_null()) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007066 ASSERT(holder->IsJSObject());
7067 return *holder;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007068 }
7069
7070 // No intermediate context found. Use global object by default.
7071 return Top::context()->global();
7072}
7073
7074
ager@chromium.orga1645e22009-09-09 19:27:10 +00007075// A mechanism to return a pair of Object pointers in registers (if possible).
7076// How this is achieved is calling convention-dependent.
7077// All currently supported x86 compiles uses calling conventions that are cdecl
7078// variants where a 64-bit value is returned in two 32-bit registers
7079// (edx:eax on ia32, r1:r0 on ARM).
7080// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
7081// In Win64 calling convention, a struct of two pointers is returned in memory,
7082// allocated by the caller, and passed as a pointer in a hidden first parameter.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007083#ifdef V8_HOST_ARCH_64_BIT
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007084struct ObjectPair {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007085 MaybeObject* x;
7086 MaybeObject* y;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007087};
ager@chromium.orga1645e22009-09-09 19:27:10 +00007088
lrn@chromium.org303ada72010-10-27 09:33:13 +00007089static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007090 ObjectPair result = {x, y};
ager@chromium.orga1645e22009-09-09 19:27:10 +00007091 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
7092 // In Win64 they are assigned to a hidden first argument.
7093 return result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007094}
7095#else
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007096typedef uint64_t ObjectPair;
lrn@chromium.org303ada72010-10-27 09:33:13 +00007097static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007098 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007099 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007100}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007101#endif
7102
7103
lrn@chromium.org303ada72010-10-27 09:33:13 +00007104static inline MaybeObject* Unhole(MaybeObject* x,
7105 PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007106 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
7107 USE(attributes);
7108 return x->IsTheHole() ? Heap::undefined_value() : x;
7109}
7110
7111
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007112static JSObject* ComputeReceiverForNonGlobal(JSObject* holder) {
7113 ASSERT(!holder->IsGlobalObject());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007114 Context* top = Top::context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007115 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007116 JSFunction* context_extension_function =
7117 top->global_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007118 // If the holder isn't a context extension object, we just return it
7119 // as the receiver. This allows arguments objects to be used as
7120 // receivers, but only if they are put in the context scope chain
7121 // explicitly via a with-statement.
7122 Object* constructor = holder->map()->constructor();
7123 if (constructor != context_extension_function) return holder;
7124 // Fall back to using the global object as the receiver if the
7125 // property turns out to be a local variable allocated in a context
7126 // extension object - introduced via eval.
7127 return top->global()->global_receiver();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007128}
7129
7130
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007131static ObjectPair LoadContextSlotHelper(Arguments args, bool throw_error) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007132 HandleScope scope;
ager@chromium.orga1645e22009-09-09 19:27:10 +00007133 ASSERT_EQ(2, args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007134
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007135 if (!args[0]->IsContext() || !args[1]->IsString()) {
ager@chromium.org3e875802009-06-29 08:26:34 +00007136 return MakePair(Top::ThrowIllegalOperation(), NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007137 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007138 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007139 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007140
7141 int index;
7142 PropertyAttributes attributes;
7143 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007144 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007145 context->Lookup(name, flags, &index, &attributes);
7146
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007147 // If the index is non-negative, the slot has been found in a local
7148 // variable or a parameter. Read it from the context object or the
7149 // arguments object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007150 if (index >= 0) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007151 // If the "property" we were looking for is a local variable or an
7152 // argument in a context, the receiver is the global object; see
7153 // ECMA-262, 3rd., 10.1.6 and 10.2.3.
7154 JSObject* receiver = Top::context()->global()->global_receiver();
lrn@chromium.org303ada72010-10-27 09:33:13 +00007155 MaybeObject* value = (holder->IsContext())
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007156 ? Context::cast(*holder)->get(index)
7157 : JSObject::cast(*holder)->GetElement(index);
7158 return MakePair(Unhole(value, attributes), receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007159 }
7160
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007161 // If the holder is found, we read the property from it.
7162 if (!holder.is_null() && holder->IsJSObject()) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007163 ASSERT(Handle<JSObject>::cast(holder)->HasProperty(*name));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007164 JSObject* object = JSObject::cast(*holder);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007165 JSObject* receiver;
7166 if (object->IsGlobalObject()) {
7167 receiver = GlobalObject::cast(object)->global_receiver();
7168 } else if (context->is_exception_holder(*holder)) {
7169 receiver = Top::context()->global()->global_receiver();
7170 } else {
7171 receiver = ComputeReceiverForNonGlobal(object);
7172 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007173 // No need to unhole the value here. This is taken care of by the
7174 // GetProperty function.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007175 MaybeObject* value = object->GetProperty(*name);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007176 return MakePair(value, receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007177 }
7178
7179 if (throw_error) {
7180 // The property doesn't exist - throw exception.
7181 Handle<Object> reference_error =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007182 Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007183 return MakePair(Top::Throw(*reference_error), NULL);
7184 } else {
7185 // The property doesn't exist - return undefined
7186 return MakePair(Heap::undefined_value(), Heap::undefined_value());
7187 }
7188}
7189
7190
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007191static ObjectPair Runtime_LoadContextSlot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007192 return LoadContextSlotHelper(args, true);
7193}
7194
7195
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007196static ObjectPair Runtime_LoadContextSlotNoReferenceError(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007197 return LoadContextSlotHelper(args, false);
7198}
7199
7200
lrn@chromium.org303ada72010-10-27 09:33:13 +00007201static MaybeObject* Runtime_StoreContextSlot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007202 HandleScope scope;
7203 ASSERT(args.length() == 3);
7204
7205 Handle<Object> value(args[0]);
7206 CONVERT_ARG_CHECKED(Context, context, 1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007207 CONVERT_ARG_CHECKED(String, name, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007208
7209 int index;
7210 PropertyAttributes attributes;
7211 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007212 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007213 context->Lookup(name, flags, &index, &attributes);
7214
7215 if (index >= 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007216 if (holder->IsContext()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007217 // Ignore if read_only variable.
7218 if ((attributes & READ_ONLY) == 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007219 Handle<Context>::cast(holder)->set(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007220 }
7221 } else {
7222 ASSERT((attributes & READ_ONLY) == 0);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007223 Handle<JSObject>::cast(holder)->SetElement(index, *value)->
7224 ToObjectUnchecked();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007225 }
7226 return *value;
7227 }
7228
7229 // Slow case: The property is not in a FixedArray context.
7230 // It is either in an JSObject extension context or it was not found.
7231 Handle<JSObject> context_ext;
7232
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007233 if (!holder.is_null()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007234 // The property exists in the extension context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007235 context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007236 } else {
7237 // The property was not found. It needs to be stored in the global context.
7238 ASSERT(attributes == ABSENT);
7239 attributes = NONE;
7240 context_ext = Handle<JSObject>(Top::context()->global());
7241 }
7242
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007243 // Set the property, but ignore if read_only variable on the context
7244 // extension object itself.
7245 if ((attributes & READ_ONLY) == 0 ||
7246 (context_ext->GetLocalPropertyAttribute(*name) == ABSENT)) {
whesse@chromium.org023421e2010-12-21 12:19:12 +00007247 Handle<Object> set = SetProperty(context_ext, name, value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007248 if (set.is_null()) {
7249 // Failure::Exception is converted to a null handle in the
7250 // handle-based methods such as SetProperty. We therefore need
7251 // to convert null handles back to exceptions.
7252 ASSERT(Top::has_pending_exception());
7253 return Failure::Exception();
7254 }
7255 }
7256 return *value;
7257}
7258
7259
lrn@chromium.org303ada72010-10-27 09:33:13 +00007260static MaybeObject* Runtime_Throw(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007261 HandleScope scope;
7262 ASSERT(args.length() == 1);
7263
7264 return Top::Throw(args[0]);
7265}
7266
7267
lrn@chromium.org303ada72010-10-27 09:33:13 +00007268static MaybeObject* Runtime_ReThrow(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007269 HandleScope scope;
7270 ASSERT(args.length() == 1);
7271
7272 return Top::ReThrow(args[0]);
7273}
7274
7275
lrn@chromium.org303ada72010-10-27 09:33:13 +00007276static MaybeObject* Runtime_PromoteScheduledException(Arguments args) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007277 ASSERT_EQ(0, args.length());
7278 return Top::PromoteScheduledException();
7279}
7280
7281
lrn@chromium.org303ada72010-10-27 09:33:13 +00007282static MaybeObject* Runtime_ThrowReferenceError(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007283 HandleScope scope;
7284 ASSERT(args.length() == 1);
7285
7286 Handle<Object> name(args[0]);
7287 Handle<Object> reference_error =
7288 Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
7289 return Top::Throw(*reference_error);
7290}
7291
7292
lrn@chromium.org303ada72010-10-27 09:33:13 +00007293static MaybeObject* Runtime_StackOverflow(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007294 NoHandleAllocation na;
7295 return Top::StackOverflow();
7296}
7297
7298
lrn@chromium.org303ada72010-10-27 09:33:13 +00007299static MaybeObject* Runtime_StackGuard(Arguments args) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00007300 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007301
7302 // First check if this is a real stack overflow.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00007303 if (StackGuard::IsStackOverflow()) {
7304 return Runtime_StackOverflow(args);
7305 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007306
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007307 return Execution::HandleStackGuardInterrupt();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007308}
7309
7310
7311// NOTE: These PrintXXX functions are defined for all builds (not just
7312// DEBUG builds) because we may want to be able to trace function
7313// calls in all modes.
7314static void PrintString(String* str) {
7315 // not uncommon to have empty strings
7316 if (str->length() > 0) {
7317 SmartPointer<char> s =
7318 str->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
7319 PrintF("%s", *s);
7320 }
7321}
7322
7323
7324static void PrintObject(Object* obj) {
7325 if (obj->IsSmi()) {
7326 PrintF("%d", Smi::cast(obj)->value());
7327 } else if (obj->IsString() || obj->IsSymbol()) {
7328 PrintString(String::cast(obj));
7329 } else if (obj->IsNumber()) {
7330 PrintF("%g", obj->Number());
7331 } else if (obj->IsFailure()) {
7332 PrintF("<failure>");
7333 } else if (obj->IsUndefined()) {
7334 PrintF("<undefined>");
7335 } else if (obj->IsNull()) {
7336 PrintF("<null>");
7337 } else if (obj->IsTrue()) {
7338 PrintF("<true>");
7339 } else if (obj->IsFalse()) {
7340 PrintF("<false>");
7341 } else {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007342 PrintF("%p", reinterpret_cast<void*>(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007343 }
7344}
7345
7346
7347static int StackSize() {
7348 int n = 0;
7349 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
7350 return n;
7351}
7352
7353
7354static void PrintTransition(Object* result) {
7355 // indentation
7356 { const int nmax = 80;
7357 int n = StackSize();
7358 if (n <= nmax)
7359 PrintF("%4d:%*s", n, n, "");
7360 else
7361 PrintF("%4d:%*s", n, nmax, "...");
7362 }
7363
7364 if (result == NULL) {
7365 // constructor calls
7366 JavaScriptFrameIterator it;
7367 JavaScriptFrame* frame = it.frame();
7368 if (frame->IsConstructor()) PrintF("new ");
7369 // function name
7370 Object* fun = frame->function();
7371 if (fun->IsJSFunction()) {
7372 PrintObject(JSFunction::cast(fun)->shared()->name());
7373 } else {
7374 PrintObject(fun);
7375 }
7376 // function arguments
7377 // (we are intentionally only printing the actually
7378 // supplied parameters, not all parameters required)
7379 PrintF("(this=");
7380 PrintObject(frame->receiver());
7381 const int length = frame->GetProvidedParametersCount();
7382 for (int i = 0; i < length; i++) {
7383 PrintF(", ");
7384 PrintObject(frame->GetParameter(i));
7385 }
7386 PrintF(") {\n");
7387
7388 } else {
7389 // function result
7390 PrintF("} -> ");
7391 PrintObject(result);
7392 PrintF("\n");
7393 }
7394}
7395
7396
lrn@chromium.org303ada72010-10-27 09:33:13 +00007397static MaybeObject* Runtime_TraceEnter(Arguments args) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007398 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007399 NoHandleAllocation ha;
7400 PrintTransition(NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007401 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007402}
7403
7404
lrn@chromium.org303ada72010-10-27 09:33:13 +00007405static MaybeObject* Runtime_TraceExit(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007406 NoHandleAllocation ha;
7407 PrintTransition(args[0]);
7408 return args[0]; // return TOS
7409}
7410
7411
lrn@chromium.org303ada72010-10-27 09:33:13 +00007412static MaybeObject* Runtime_DebugPrint(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007413 NoHandleAllocation ha;
7414 ASSERT(args.length() == 1);
7415
7416#ifdef DEBUG
7417 if (args[0]->IsString()) {
7418 // If we have a string, assume it's a code "marker"
7419 // and print some interesting cpu debugging info.
7420 JavaScriptFrameIterator it;
7421 JavaScriptFrame* frame = it.frame();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00007422 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
7423 frame->fp(), frame->sp(), frame->caller_sp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007424 } else {
7425 PrintF("DebugPrint: ");
7426 }
7427 args[0]->Print();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00007428 if (args[0]->IsHeapObject()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007429 PrintF("\n");
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00007430 HeapObject::cast(args[0])->map()->Print();
7431 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007432#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007433 // ShortPrint is available in release mode. Print is not.
7434 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007435#endif
7436 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00007437 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007438
7439 return args[0]; // return TOS
7440}
7441
7442
lrn@chromium.org303ada72010-10-27 09:33:13 +00007443static MaybeObject* Runtime_DebugTrace(Arguments args) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007444 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007445 NoHandleAllocation ha;
7446 Top::PrintStack();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007447 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007448}
7449
7450
lrn@chromium.org303ada72010-10-27 09:33:13 +00007451static MaybeObject* Runtime_DateCurrentTime(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007452 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00007453 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007454
7455 // According to ECMA-262, section 15.9.1, page 117, the precision of
7456 // the number in a Date object representing a particular instant in
7457 // time is milliseconds. Therefore, we floor the result of getting
7458 // the OS time.
7459 double millis = floor(OS::TimeCurrentMillis());
7460 return Heap::NumberFromDouble(millis);
7461}
7462
7463
lrn@chromium.org303ada72010-10-27 09:33:13 +00007464static MaybeObject* Runtime_DateParseString(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007465 HandleScope scope;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007466 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007467
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007468 CONVERT_ARG_CHECKED(String, str, 0);
7469 FlattenString(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007470
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007471 CONVERT_ARG_CHECKED(JSArray, output, 1);
7472 RUNTIME_ASSERT(output->HasFastElements());
7473
7474 AssertNoAllocation no_allocation;
7475
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007476 FixedArray* output_array = FixedArray::cast(output->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007477 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
7478 bool result;
ager@chromium.org5ec48922009-05-05 07:25:34 +00007479 if (str->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007480 result = DateParser::Parse(str->ToAsciiVector(), output_array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007481 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00007482 ASSERT(str->IsTwoByteRepresentation());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007483 result = DateParser::Parse(str->ToUC16Vector(), output_array);
7484 }
7485
7486 if (result) {
7487 return *output;
7488 } else {
7489 return Heap::null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007490 }
7491}
7492
7493
lrn@chromium.org303ada72010-10-27 09:33:13 +00007494static MaybeObject* Runtime_DateLocalTimezone(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007495 NoHandleAllocation ha;
7496 ASSERT(args.length() == 1);
7497
7498 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00007499 const char* zone = OS::LocalTimezone(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007500 return Heap::AllocateStringFromUtf8(CStrVector(zone));
7501}
7502
7503
lrn@chromium.org303ada72010-10-27 09:33:13 +00007504static MaybeObject* Runtime_DateLocalTimeOffset(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007505 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00007506 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007507
7508 return Heap::NumberFromDouble(OS::LocalTimeOffset());
7509}
7510
7511
lrn@chromium.org303ada72010-10-27 09:33:13 +00007512static MaybeObject* Runtime_DateDaylightSavingsOffset(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007513 NoHandleAllocation ha;
7514 ASSERT(args.length() == 1);
7515
7516 CONVERT_DOUBLE_CHECKED(x, args[0]);
7517 return Heap::NumberFromDouble(OS::DaylightSavingsOffset(x));
7518}
7519
7520
lrn@chromium.org303ada72010-10-27 09:33:13 +00007521static MaybeObject* Runtime_GlobalReceiver(Arguments args) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007522 ASSERT(args.length() == 1);
7523 Object* global = args[0];
7524 if (!global->IsJSGlobalObject()) return Heap::null_value();
7525 return JSGlobalObject::cast(global)->global_receiver();
7526}
7527
7528
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00007529static MaybeObject* Runtime_ParseJson(Arguments args) {
7530 HandleScope scope;
7531 ASSERT_EQ(1, args.length());
7532 CONVERT_ARG_CHECKED(String, source, 0);
7533
7534 Handle<Object> result = JsonParser::Parse(source);
7535 if (result.is_null()) {
7536 // Syntax error or stack overflow in scanner.
7537 ASSERT(Top::has_pending_exception());
7538 return Failure::Exception();
7539 }
7540 return *result;
7541}
7542
7543
lrn@chromium.org303ada72010-10-27 09:33:13 +00007544static MaybeObject* Runtime_CompileString(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007545 HandleScope scope;
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00007546 ASSERT_EQ(1, args.length());
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00007547 CONVERT_ARG_CHECKED(String, source, 0);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007548
ager@chromium.org381abbb2009-02-25 13:23:22 +00007549 // Compile source string in the global context.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007550 Handle<Context> context(Top::context()->global_context());
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007551 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(source,
7552 context,
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00007553 true);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007554 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007555 Handle<JSFunction> fun =
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007556 Factory::NewFunctionFromSharedFunctionInfo(shared, context, NOT_TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007557 return *fun;
7558}
7559
7560
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00007561static ObjectPair CompileGlobalEval(Handle<String> source,
7562 Handle<Object> receiver) {
7563 // Deal with a normal eval call with a string argument. Compile it
7564 // and return the compiled function bound in the local context.
7565 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
7566 source,
7567 Handle<Context>(Top::context()),
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00007568 Top::context()->IsGlobalContext());
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00007569 if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
7570 Handle<JSFunction> compiled = Factory::NewFunctionFromSharedFunctionInfo(
7571 shared,
7572 Handle<Context>(Top::context()),
7573 NOT_TENURED);
7574 return MakePair(*compiled, *receiver);
7575}
7576
7577
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007578static ObjectPair Runtime_ResolvePossiblyDirectEval(Arguments args) {
7579 ASSERT(args.length() == 3);
7580 if (!args[0]->IsJSFunction()) {
7581 return MakePair(Top::ThrowIllegalOperation(), NULL);
7582 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007583
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007584 HandleScope scope;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007585 Handle<JSFunction> callee = args.at<JSFunction>(0);
7586 Handle<Object> receiver; // Will be overwritten.
7587
7588 // Compute the calling context.
7589 Handle<Context> context = Handle<Context>(Top::context());
7590#ifdef DEBUG
7591 // Make sure Top::context() agrees with the old code that traversed
7592 // the stack frames to compute the context.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007593 StackFrameLocator locator;
7594 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007595 ASSERT(Context::cast(frame->context()) == *context);
7596#endif
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007597
7598 // Find where the 'eval' symbol is bound. It is unaliased only if
7599 // it is bound in the global context.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007600 int index = -1;
7601 PropertyAttributes attributes = ABSENT;
7602 while (true) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007603 receiver = context->Lookup(Factory::eval_symbol(), FOLLOW_PROTOTYPE_CHAIN,
7604 &index, &attributes);
iposva@chromium.org245aa852009-02-10 00:49:54 +00007605 // Stop search when eval is found or when the global context is
7606 // reached.
7607 if (attributes != ABSENT || context->IsGlobalContext()) break;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007608 if (context->is_function_context()) {
7609 context = Handle<Context>(Context::cast(context->closure()->context()));
7610 } else {
7611 context = Handle<Context>(context->previous());
7612 }
7613 }
7614
iposva@chromium.org245aa852009-02-10 00:49:54 +00007615 // If eval could not be resolved, it has been deleted and we need to
7616 // throw a reference error.
7617 if (attributes == ABSENT) {
7618 Handle<Object> name = Factory::eval_symbol();
7619 Handle<Object> reference_error =
7620 Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007621 return MakePair(Top::Throw(*reference_error), NULL);
iposva@chromium.org245aa852009-02-10 00:49:54 +00007622 }
7623
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007624 if (!context->IsGlobalContext()) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007625 // 'eval' is not bound in the global context. Just call the function
7626 // with the given arguments. This is not necessarily the global eval.
7627 if (receiver->IsContext()) {
7628 context = Handle<Context>::cast(receiver);
7629 receiver = Handle<Object>(context->get(index));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007630 } else if (receiver->IsJSContextExtensionObject()) {
7631 receiver = Handle<JSObject>(Top::context()->global()->global_receiver());
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007632 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007633 return MakePair(*callee, *receiver);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007634 }
7635
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007636 // 'eval' is bound in the global context, but it may have been overwritten.
7637 // Compare it to the builtin 'GlobalEval' function to make sure.
7638 if (*callee != Top::global_context()->global_eval_fun() ||
7639 !args[1]->IsString()) {
7640 return MakePair(*callee, Top::context()->global()->global_receiver());
7641 }
7642
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00007643 return CompileGlobalEval(args.at<String>(1), args.at<Object>(2));
7644}
7645
7646
7647static ObjectPair Runtime_ResolvePossiblyDirectEvalNoLookup(Arguments args) {
7648 ASSERT(args.length() == 3);
7649 if (!args[0]->IsJSFunction()) {
7650 return MakePair(Top::ThrowIllegalOperation(), NULL);
7651 }
7652
7653 HandleScope scope;
7654 Handle<JSFunction> callee = args.at<JSFunction>(0);
7655
7656 // 'eval' is bound in the global context, but it may have been overwritten.
7657 // Compare it to the builtin 'GlobalEval' function to make sure.
7658 if (*callee != Top::global_context()->global_eval_fun() ||
7659 !args[1]->IsString()) {
7660 return MakePair(*callee, Top::context()->global()->global_receiver());
7661 }
7662
7663 return CompileGlobalEval(args.at<String>(1), args.at<Object>(2));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007664}
7665
7666
lrn@chromium.org303ada72010-10-27 09:33:13 +00007667static MaybeObject* Runtime_SetNewFunctionAttributes(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007668 // This utility adjusts the property attributes for newly created Function
7669 // object ("new Function(...)") by changing the map.
7670 // All it does is changing the prototype property to enumerable
7671 // as specified in ECMA262, 15.3.5.2.
7672 HandleScope scope;
7673 ASSERT(args.length() == 1);
7674 CONVERT_ARG_CHECKED(JSFunction, func, 0);
7675 ASSERT(func->map()->instance_type() ==
7676 Top::function_instance_map()->instance_type());
7677 ASSERT(func->map()->instance_size() ==
7678 Top::function_instance_map()->instance_size());
7679 func->set_map(*Top::function_instance_map());
7680 return *func;
7681}
7682
7683
lrn@chromium.org303ada72010-10-27 09:33:13 +00007684static MaybeObject* Runtime_AllocateInNewSpace(Arguments args) {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00007685 // Allocate a block of memory in NewSpace (filled with a filler).
7686 // Use as fallback for allocation in generated code when NewSpace
7687 // is full.
7688 ASSERT(args.length() == 1);
7689 CONVERT_ARG_CHECKED(Smi, size_smi, 0);
7690 int size = size_smi->value();
7691 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
7692 RUNTIME_ASSERT(size > 0);
7693 static const int kMinFreeNewSpaceAfterGC =
7694 Heap::InitialSemiSpaceSize() * 3/4;
7695 RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007696 Object* allocation;
7697 { MaybeObject* maybe_allocation = Heap::new_space()->AllocateRaw(size);
7698 if (maybe_allocation->ToObject(&allocation)) {
7699 Heap::CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
7700 }
7701 return maybe_allocation;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00007702 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00007703}
7704
7705
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007706// Push an object unto an array of objects if it is not already in the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007707// array. Returns true if the element was pushed on the stack and
7708// false otherwise.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007709static MaybeObject* Runtime_PushIfAbsent(Arguments args) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007710 ASSERT(args.length() == 2);
7711 CONVERT_CHECKED(JSArray, array, args[0]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007712 CONVERT_CHECKED(JSObject, element, args[1]);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007713 RUNTIME_ASSERT(array->HasFastElements());
7714 int length = Smi::cast(array->length())->value();
7715 FixedArray* elements = FixedArray::cast(array->elements());
7716 for (int i = 0; i < length; i++) {
7717 if (elements->get(i) == element) return Heap::false_value();
7718 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00007719 Object* obj;
7720 { MaybeObject* maybe_obj = array->SetFastElement(length, element);
7721 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7722 }
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007723 return Heap::true_value();
7724}
7725
7726
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007727/**
7728 * A simple visitor visits every element of Array's.
7729 * The backend storage can be a fixed array for fast elements case,
7730 * or a dictionary for sparse array. Since Dictionary is a subtype
7731 * of FixedArray, the class can be used by both fast and slow cases.
7732 * The second parameter of the constructor, fast_elements, specifies
7733 * whether the storage is a FixedArray or Dictionary.
7734 *
7735 * An index limit is used to deal with the situation that a result array
7736 * length overflows 32-bit non-negative integer.
7737 */
7738class ArrayConcatVisitor {
7739 public:
7740 ArrayConcatVisitor(Handle<FixedArray> storage,
7741 uint32_t index_limit,
7742 bool fast_elements) :
7743 storage_(storage), index_limit_(index_limit),
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007744 index_offset_(0), fast_elements_(fast_elements) { }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007745
7746 void visit(uint32_t i, Handle<Object> elm) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007747 if (i >= index_limit_ - index_offset_) return;
7748 uint32_t index = index_offset_ + i;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007749
7750 if (fast_elements_) {
7751 ASSERT(index < static_cast<uint32_t>(storage_->length()));
7752 storage_->set(index, *elm);
7753
7754 } else {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00007755 Handle<NumberDictionary> dict = Handle<NumberDictionary>::cast(storage_);
7756 Handle<NumberDictionary> result =
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007757 Factory::DictionaryAtNumberPut(dict, index, elm);
7758 if (!result.is_identical_to(dict))
7759 storage_ = result;
7760 }
7761 }
7762
7763 void increase_index_offset(uint32_t delta) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007764 if (index_limit_ - index_offset_ < delta) {
7765 index_offset_ = index_limit_;
7766 } else {
7767 index_offset_ += delta;
7768 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007769 }
7770
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00007771 Handle<FixedArray> storage() { return storage_; }
7772
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007773 private:
7774 Handle<FixedArray> storage_;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007775 // Limit on the accepted indices. Elements with indices larger than the
7776 // limit are ignored by the visitor.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007777 uint32_t index_limit_;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007778 // Index after last seen index. Always less than or equal to index_limit_.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007779 uint32_t index_offset_;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00007780 const bool fast_elements_;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007781};
7782
7783
ager@chromium.org3811b432009-10-28 14:53:37 +00007784template<class ExternalArrayClass, class ElementType>
7785static uint32_t IterateExternalArrayElements(Handle<JSObject> receiver,
7786 bool elements_are_ints,
7787 bool elements_are_guaranteed_smis,
7788 uint32_t range,
7789 ArrayConcatVisitor* visitor) {
7790 Handle<ExternalArrayClass> array(
7791 ExternalArrayClass::cast(receiver->elements()));
7792 uint32_t len = Min(static_cast<uint32_t>(array->length()), range);
7793
7794 if (visitor != NULL) {
7795 if (elements_are_ints) {
7796 if (elements_are_guaranteed_smis) {
7797 for (uint32_t j = 0; j < len; j++) {
7798 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get(j))));
7799 visitor->visit(j, e);
7800 }
7801 } else {
7802 for (uint32_t j = 0; j < len; j++) {
7803 int64_t val = static_cast<int64_t>(array->get(j));
7804 if (Smi::IsValid(static_cast<intptr_t>(val))) {
7805 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
7806 visitor->visit(j, e);
7807 } else {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007808 Handle<Object> e =
7809 Factory::NewNumber(static_cast<ElementType>(val));
ager@chromium.org3811b432009-10-28 14:53:37 +00007810 visitor->visit(j, e);
7811 }
7812 }
7813 }
7814 } else {
7815 for (uint32_t j = 0; j < len; j++) {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007816 Handle<Object> e = Factory::NewNumber(array->get(j));
ager@chromium.org3811b432009-10-28 14:53:37 +00007817 visitor->visit(j, e);
7818 }
7819 }
7820 }
7821
7822 return len;
7823}
7824
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007825/**
7826 * A helper function that visits elements of a JSObject. Only elements
7827 * whose index between 0 and range (exclusive) are visited.
7828 *
7829 * If the third parameter, visitor, is not NULL, the visitor is called
7830 * with parameters, 'visitor_index_offset + element index' and the element.
7831 *
7832 * It returns the number of visisted elements.
7833 */
7834static uint32_t IterateElements(Handle<JSObject> receiver,
7835 uint32_t range,
7836 ArrayConcatVisitor* visitor) {
7837 uint32_t num_of_elements = 0;
7838
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007839 switch (receiver->GetElementsKind()) {
7840 case JSObject::FAST_ELEMENTS: {
7841 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
7842 uint32_t len = elements->length();
7843 if (range < len) {
7844 len = range;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007845 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007846
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007847 for (uint32_t j = 0; j < len; j++) {
7848 Handle<Object> e(elements->get(j));
7849 if (!e->IsTheHole()) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007850 num_of_elements++;
7851 if (visitor) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007852 visitor->visit(j, e);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007853 }
7854 }
7855 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007856 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007857 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007858 case JSObject::PIXEL_ELEMENTS: {
7859 Handle<PixelArray> pixels(PixelArray::cast(receiver->elements()));
7860 uint32_t len = pixels->length();
7861 if (range < len) {
7862 len = range;
7863 }
7864
7865 for (uint32_t j = 0; j < len; j++) {
7866 num_of_elements++;
7867 if (visitor != NULL) {
7868 Handle<Smi> e(Smi::FromInt(pixels->get(j)));
7869 visitor->visit(j, e);
7870 }
7871 }
7872 break;
7873 }
ager@chromium.org3811b432009-10-28 14:53:37 +00007874 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
7875 num_of_elements =
7876 IterateExternalArrayElements<ExternalByteArray, int8_t>(
7877 receiver, true, true, range, visitor);
7878 break;
7879 }
7880 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
7881 num_of_elements =
7882 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
7883 receiver, true, true, range, visitor);
7884 break;
7885 }
7886 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
7887 num_of_elements =
7888 IterateExternalArrayElements<ExternalShortArray, int16_t>(
7889 receiver, true, true, range, visitor);
7890 break;
7891 }
7892 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
7893 num_of_elements =
7894 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
7895 receiver, true, true, range, visitor);
7896 break;
7897 }
7898 case JSObject::EXTERNAL_INT_ELEMENTS: {
7899 num_of_elements =
7900 IterateExternalArrayElements<ExternalIntArray, int32_t>(
7901 receiver, true, false, range, visitor);
7902 break;
7903 }
7904 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
7905 num_of_elements =
7906 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
7907 receiver, true, false, range, visitor);
7908 break;
7909 }
7910 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
7911 num_of_elements =
7912 IterateExternalArrayElements<ExternalFloatArray, float>(
7913 receiver, false, false, range, visitor);
7914 break;
7915 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007916 case JSObject::DICTIONARY_ELEMENTS: {
7917 Handle<NumberDictionary> dict(receiver->element_dictionary());
7918 uint32_t capacity = dict->Capacity();
7919 for (uint32_t j = 0; j < capacity; j++) {
7920 Handle<Object> k(dict->KeyAt(j));
7921 if (dict->IsKey(*k)) {
7922 ASSERT(k->IsNumber());
7923 uint32_t index = static_cast<uint32_t>(k->Number());
7924 if (index < range) {
7925 num_of_elements++;
7926 if (visitor) {
7927 visitor->visit(index, Handle<Object>(dict->ValueAt(j)));
7928 }
7929 }
7930 }
7931 }
7932 break;
7933 }
7934 default:
7935 UNREACHABLE();
7936 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007937 }
7938
7939 return num_of_elements;
7940}
7941
7942
7943/**
7944 * A helper function that visits elements of an Array object, and elements
7945 * on its prototypes.
7946 *
7947 * Elements on prototypes are visited first, and only elements whose indices
7948 * less than Array length are visited.
7949 *
7950 * If a ArrayConcatVisitor object is given, the visitor is called with
7951 * parameters, element's index + visitor_index_offset and the element.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007952 *
7953 * The returned number of elements is an upper bound on the actual number
7954 * of elements added. If the same element occurs in more than one object
7955 * in the array's prototype chain, it will be counted more than once, but
7956 * will only occur once in the result.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007957 */
7958static uint32_t IterateArrayAndPrototypeElements(Handle<JSArray> array,
7959 ArrayConcatVisitor* visitor) {
7960 uint32_t range = static_cast<uint32_t>(array->length()->Number());
7961 Handle<Object> obj = array;
7962
7963 static const int kEstimatedPrototypes = 3;
7964 List< Handle<JSObject> > objects(kEstimatedPrototypes);
7965
7966 // Visit prototype first. If an element on the prototype is shadowed by
7967 // the inheritor using the same index, the ArrayConcatVisitor visits
7968 // the prototype element before the shadowing element.
7969 // The visitor can simply overwrite the old value by new value using
7970 // the same index. This follows Array::concat semantics.
7971 while (!obj->IsNull()) {
7972 objects.Add(Handle<JSObject>::cast(obj));
7973 obj = Handle<Object>(obj->GetPrototype());
7974 }
7975
7976 uint32_t nof_elements = 0;
7977 for (int i = objects.length() - 1; i >= 0; i--) {
7978 Handle<JSObject> obj = objects[i];
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007979 uint32_t encountered_elements =
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007980 IterateElements(Handle<JSObject>::cast(obj), range, visitor);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007981
7982 if (encountered_elements > JSObject::kMaxElementCount - nof_elements) {
7983 nof_elements = JSObject::kMaxElementCount;
7984 } else {
7985 nof_elements += encountered_elements;
7986 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007987 }
7988
7989 return nof_elements;
7990}
7991
7992
7993/**
7994 * A helper function of Runtime_ArrayConcat.
7995 *
7996 * The first argument is an Array of arrays and objects. It is the
7997 * same as the arguments array of Array::concat JS function.
7998 *
7999 * If an argument is an Array object, the function visits array
8000 * elements. If an argument is not an Array object, the function
8001 * visits the object as if it is an one-element array.
8002 *
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008003 * If the result array index overflows 32-bit unsigned integer, the rounded
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008004 * non-negative number is used as new length. For example, if one
8005 * array length is 2^32 - 1, second array length is 1, the
8006 * concatenated array length is 0.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008007 * TODO(lrn) Change length behavior to ECMAScript 5 specification (length
8008 * is one more than the last array index to get a value assigned).
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008009 */
8010static uint32_t IterateArguments(Handle<JSArray> arguments,
8011 ArrayConcatVisitor* visitor) {
8012 uint32_t visited_elements = 0;
8013 uint32_t num_of_args = static_cast<uint32_t>(arguments->length()->Number());
8014
8015 for (uint32_t i = 0; i < num_of_args; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008016 Object *element;
8017 MaybeObject* maybe_element = arguments->GetElement(i);
8018 // This if() is not expected to fail, but we have the check in the
8019 // interest of hardening the runtime calls.
8020 if (maybe_element->ToObject(&element)) {
8021 Handle<Object> obj(element);
8022 if (obj->IsJSArray()) {
8023 Handle<JSArray> array = Handle<JSArray>::cast(obj);
8024 uint32_t len = static_cast<uint32_t>(array->length()->Number());
8025 uint32_t nof_elements =
8026 IterateArrayAndPrototypeElements(array, visitor);
8027 // Total elements of array and its prototype chain can be more than
8028 // the array length, but ArrayConcat can only concatenate at most
8029 // the array length number of elements. We use the length as an estimate
8030 // for the actual number of elements added.
8031 uint32_t added_elements = (nof_elements > len) ? len : nof_elements;
8032 if (JSArray::kMaxElementCount - visited_elements < added_elements) {
8033 visited_elements = JSArray::kMaxElementCount;
8034 } else {
8035 visited_elements += added_elements;
8036 }
8037 if (visitor) visitor->increase_index_offset(len);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008038 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008039 if (visitor) {
8040 visitor->visit(0, obj);
8041 visitor->increase_index_offset(1);
8042 }
8043 if (visited_elements < JSArray::kMaxElementCount) {
8044 visited_elements++;
8045 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008046 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008047 }
8048 }
8049 return visited_elements;
8050}
8051
8052
8053/**
8054 * Array::concat implementation.
8055 * See ECMAScript 262, 15.4.4.4.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008056 * TODO(lrn): Fix non-compliance for very large concatenations and update to
8057 * following the ECMAScript 5 specification.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008058 */
lrn@chromium.org303ada72010-10-27 09:33:13 +00008059static MaybeObject* Runtime_ArrayConcat(Arguments args) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008060 ASSERT(args.length() == 1);
8061 HandleScope handle_scope;
8062
8063 CONVERT_CHECKED(JSArray, arg_arrays, args[0]);
8064 Handle<JSArray> arguments(arg_arrays);
8065
8066 // Pass 1: estimate the number of elements of the result
8067 // (it could be more than real numbers if prototype has elements).
8068 uint32_t result_length = 0;
8069 uint32_t num_of_args = static_cast<uint32_t>(arguments->length()->Number());
8070
8071 { AssertNoAllocation nogc;
8072 for (uint32_t i = 0; i < num_of_args; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008073 Object* obj;
8074 MaybeObject* maybe_object = arguments->GetElement(i);
8075 // This if() is not expected to fail, but we have the check in the
8076 // interest of hardening the runtime calls.
8077 if (maybe_object->ToObject(&obj)) {
8078 uint32_t length_estimate;
8079 if (obj->IsJSArray()) {
8080 length_estimate =
8081 static_cast<uint32_t>(JSArray::cast(obj)->length()->Number());
8082 } else {
8083 length_estimate = 1;
8084 }
8085 if (JSObject::kMaxElementCount - result_length < length_estimate) {
8086 result_length = JSObject::kMaxElementCount;
8087 break;
8088 }
8089 result_length += length_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008090 }
8091 }
8092 }
8093
8094 // Allocate an empty array, will set length and content later.
8095 Handle<JSArray> result = Factory::NewJSArray(0);
8096
8097 uint32_t estimate_nof_elements = IterateArguments(arguments, NULL);
8098 // If estimated number of elements is more than half of length, a
8099 // fixed array (fast case) is more time and space-efficient than a
8100 // dictionary.
8101 bool fast_case = (estimate_nof_elements * 2) >= result_length;
8102
8103 Handle<FixedArray> storage;
8104 if (fast_case) {
8105 // The backing storage array must have non-existing elements to
8106 // preserve holes across concat operations.
8107 storage = Factory::NewFixedArrayWithHoles(result_length);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008108 Handle<Map> fast_map =
8109 Factory::GetFastElementsMap(Handle<Map>(result->map()));
8110 result->set_map(*fast_map);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008111 } else {
8112 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
8113 uint32_t at_least_space_for = estimate_nof_elements +
8114 (estimate_nof_elements >> 2);
8115 storage = Handle<FixedArray>::cast(
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00008116 Factory::NewNumberDictionary(at_least_space_for));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008117 Handle<Map> slow_map =
8118 Factory::GetSlowElementsMap(Handle<Map>(result->map()));
8119 result->set_map(*slow_map);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008120 }
8121
8122 Handle<Object> len = Factory::NewNumber(static_cast<double>(result_length));
8123
8124 ArrayConcatVisitor visitor(storage, result_length, fast_case);
8125
8126 IterateArguments(arguments, &visitor);
8127
8128 result->set_length(*len);
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00008129 // Please note the storage might have changed in the visitor.
8130 result->set_elements(*visitor.storage());
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008131
8132 return *result;
8133}
8134
8135
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008136// This will not allocate (flatten the string), but it may run
8137// very slowly for very deeply nested ConsStrings. For debugging use only.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008138static MaybeObject* Runtime_GlobalPrint(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008139 NoHandleAllocation ha;
8140 ASSERT(args.length() == 1);
8141
8142 CONVERT_CHECKED(String, string, args[0]);
8143 StringInputBuffer buffer(string);
8144 while (buffer.has_more()) {
8145 uint16_t character = buffer.GetNext();
8146 PrintF("%c", character);
8147 }
8148 return string;
8149}
8150
ager@chromium.org5ec48922009-05-05 07:25:34 +00008151// Moves all own elements of an object, that are below a limit, to positions
8152// starting at zero. All undefined values are placed after non-undefined values,
8153// and are followed by non-existing element. Does not change the length
8154// property.
8155// Returns the number of non-undefined elements collected.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008156static MaybeObject* Runtime_RemoveArrayHoles(Arguments args) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00008157 ASSERT(args.length() == 2);
8158 CONVERT_CHECKED(JSObject, object, args[0]);
8159 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
8160 return object->PrepareElementsForSort(limit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008161}
8162
8163
8164// Move contents of argument 0 (an array) to argument 1 (an array)
lrn@chromium.org303ada72010-10-27 09:33:13 +00008165static MaybeObject* Runtime_MoveArrayContents(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008166 ASSERT(args.length() == 2);
8167 CONVERT_CHECKED(JSArray, from, args[0]);
8168 CONVERT_CHECKED(JSArray, to, args[1]);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00008169 HeapObject* new_elements = from->elements();
lrn@chromium.org303ada72010-10-27 09:33:13 +00008170 MaybeObject* maybe_new_map;
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00008171 if (new_elements->map() == Heap::fixed_array_map() ||
8172 new_elements->map() == Heap::fixed_cow_array_map()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008173 maybe_new_map = to->map()->GetFastElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00008174 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008175 maybe_new_map = to->map()->GetSlowElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00008176 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00008177 Object* new_map;
8178 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00008179 to->set_map(Map::cast(new_map));
8180 to->set_elements(new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008181 to->set_length(from->length());
lrn@chromium.org303ada72010-10-27 09:33:13 +00008182 Object* obj;
8183 { MaybeObject* maybe_obj = from->ResetElements();
8184 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8185 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008186 from->set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008187 return to;
8188}
8189
8190
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008191// How many elements does this object/array have?
lrn@chromium.org303ada72010-10-27 09:33:13 +00008192static MaybeObject* Runtime_EstimateNumberOfElements(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008193 ASSERT(args.length() == 1);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008194 CONVERT_CHECKED(JSObject, object, args[0]);
8195 HeapObject* elements = object->elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008196 if (elements->IsDictionary()) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00008197 return Smi::FromInt(NumberDictionary::cast(elements)->NumberOfElements());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008198 } else if (object->IsJSArray()) {
8199 return JSArray::cast(object)->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008200 } else {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008201 return Smi::FromInt(FixedArray::cast(elements)->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008202 }
8203}
8204
8205
lrn@chromium.org303ada72010-10-27 09:33:13 +00008206static MaybeObject* Runtime_SwapElements(Arguments args) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008207 HandleScope handle_scope;
8208
8209 ASSERT_EQ(3, args.length());
8210
ager@chromium.orgac091b72010-05-05 07:34:42 +00008211 CONVERT_ARG_CHECKED(JSObject, object, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008212 Handle<Object> key1 = args.at<Object>(1);
8213 Handle<Object> key2 = args.at<Object>(2);
8214
8215 uint32_t index1, index2;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008216 if (!key1->ToArrayIndex(&index1)
8217 || !key2->ToArrayIndex(&index2)) {
ager@chromium.orgac091b72010-05-05 07:34:42 +00008218 return Top::ThrowIllegalOperation();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008219 }
8220
ager@chromium.orgac091b72010-05-05 07:34:42 +00008221 Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
8222 Handle<Object> tmp1 = GetElement(jsobject, index1);
8223 Handle<Object> tmp2 = GetElement(jsobject, index2);
8224
8225 SetElement(jsobject, index1, tmp2);
8226 SetElement(jsobject, index2, tmp1);
8227
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008228 return Heap::undefined_value();
8229}
8230
8231
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008232// Returns an array that tells you where in the [0, length) interval an array
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008233// might have elements. Can either return keys (positive integers) or
8234// intervals (pair of a negative integer (-start-1) followed by a
8235// positive (length)) or undefined values.
8236// Intervals can span over some keys that are not in the object.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008237static MaybeObject* Runtime_GetArrayKeys(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008238 ASSERT(args.length() == 2);
8239 HandleScope scope;
ager@chromium.org5ec48922009-05-05 07:25:34 +00008240 CONVERT_ARG_CHECKED(JSObject, array, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008241 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008242 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008243 // Create an array and get all the keys into it, then remove all the
8244 // keys that are not integers in the range 0 to length-1.
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008245 Handle<FixedArray> keys = GetKeysInFixedArrayFor(array, INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008246 int keys_length = keys->length();
8247 for (int i = 0; i < keys_length; i++) {
8248 Object* key = keys->get(i);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008249 uint32_t index = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008250 if (!key->ToArrayIndex(&index) || index >= length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008251 // Zap invalid keys.
8252 keys->set_undefined(i);
8253 }
8254 }
8255 return *Factory::NewJSArrayWithElements(keys);
8256 } else {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008257 ASSERT(array->HasFastElements());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008258 Handle<FixedArray> single_interval = Factory::NewFixedArray(2);
8259 // -1 means start of array.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008260 single_interval->set(0, Smi::FromInt(-1));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008261 uint32_t actual_length =
8262 static_cast<uint32_t>(FixedArray::cast(array->elements())->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +00008263 uint32_t min_length = actual_length < length ? actual_length : length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008264 Handle<Object> length_object =
ager@chromium.org5ec48922009-05-05 07:25:34 +00008265 Factory::NewNumber(static_cast<double>(min_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008266 single_interval->set(1, *length_object);
8267 return *Factory::NewJSArrayWithElements(single_interval);
8268 }
8269}
8270
8271
8272// DefineAccessor takes an optional final argument which is the
8273// property attributes (eg, DONT_ENUM, DONT_DELETE). IMPORTANT: due
8274// to the way accessors are implemented, it is set for both the getter
8275// and setter on the first call to DefineAccessor and ignored on
8276// subsequent calls.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008277static MaybeObject* Runtime_DefineAccessor(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008278 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
8279 // Compute attributes.
8280 PropertyAttributes attributes = NONE;
8281 if (args.length() == 5) {
8282 CONVERT_CHECKED(Smi, attrs, args[4]);
8283 int value = attrs->value();
8284 // Only attribute bits should be set.
8285 ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
8286 attributes = static_cast<PropertyAttributes>(value);
8287 }
8288
8289 CONVERT_CHECKED(JSObject, obj, args[0]);
8290 CONVERT_CHECKED(String, name, args[1]);
8291 CONVERT_CHECKED(Smi, flag, args[2]);
8292 CONVERT_CHECKED(JSFunction, fun, args[3]);
8293 return obj->DefineAccessor(name, flag->value() == 0, fun, attributes);
8294}
8295
8296
lrn@chromium.org303ada72010-10-27 09:33:13 +00008297static MaybeObject* Runtime_LookupAccessor(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008298 ASSERT(args.length() == 3);
8299 CONVERT_CHECKED(JSObject, obj, args[0]);
8300 CONVERT_CHECKED(String, name, args[1]);
8301 CONVERT_CHECKED(Smi, flag, args[2]);
8302 return obj->LookupAccessor(name, flag->value() == 0);
8303}
8304
8305
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008306#ifdef ENABLE_DEBUGGER_SUPPORT
lrn@chromium.org303ada72010-10-27 09:33:13 +00008307static MaybeObject* Runtime_DebugBreak(Arguments args) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008308 ASSERT(args.length() == 0);
8309 return Execution::DebugBreakHelper();
8310}
8311
8312
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008313// Helper functions for wrapping and unwrapping stack frame ids.
8314static Smi* WrapFrameId(StackFrame::Id id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +00008315 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008316 return Smi::FromInt(id >> 2);
8317}
8318
8319
8320static StackFrame::Id UnwrapFrameId(Smi* wrapped) {
8321 return static_cast<StackFrame::Id>(wrapped->value() << 2);
8322}
8323
8324
8325// Adds a JavaScript function as a debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +00008326// args[0]: debug event listener function to set or null or undefined for
8327// clearing the event listener function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008328// args[1]: object supplied during callback
lrn@chromium.org303ada72010-10-27 09:33:13 +00008329static MaybeObject* Runtime_SetDebugEventListener(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008330 ASSERT(args.length() == 2);
iposva@chromium.org245aa852009-02-10 00:49:54 +00008331 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
8332 args[0]->IsUndefined() ||
8333 args[0]->IsNull());
8334 Handle<Object> callback = args.at<Object>(0);
8335 Handle<Object> data = args.at<Object>(1);
8336 Debugger::SetEventListener(callback, data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008337
8338 return Heap::undefined_value();
8339}
8340
8341
lrn@chromium.org303ada72010-10-27 09:33:13 +00008342static MaybeObject* Runtime_Break(Arguments args) {
mads.s.ager31e71382008-08-13 09:32:07 +00008343 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008344 StackGuard::DebugBreak();
8345 return Heap::undefined_value();
8346}
8347
8348
lrn@chromium.org303ada72010-10-27 09:33:13 +00008349static MaybeObject* DebugLookupResultValue(Object* receiver, String* name,
8350 LookupResult* result,
8351 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00008352 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008353 switch (result->type()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008354 case NORMAL:
8355 value = result->holder()->GetNormalizedProperty(result);
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00008356 if (value->IsTheHole()) {
8357 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008358 }
8359 return value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00008360 case FIELD:
8361 value =
8362 JSObject::cast(
8363 result->holder())->FastPropertyAt(result->GetFieldIndex());
8364 if (value->IsTheHole()) {
8365 return Heap::undefined_value();
8366 }
8367 return value;
8368 case CONSTANT_FUNCTION:
8369 return result->GetConstantFunction();
8370 case CALLBACKS: {
8371 Object* structure = result->GetCallbackObject();
kasperl@chromium.org71affb52009-05-26 05:44:31 +00008372 if (structure->IsProxy() || structure->IsAccessorInfo()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008373 MaybeObject* maybe_value = receiver->GetPropertyWithCallback(
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00008374 receiver, structure, name, result->holder());
lrn@chromium.org303ada72010-10-27 09:33:13 +00008375 if (!maybe_value->ToObject(&value)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008376 if (maybe_value->IsRetryAfterGC()) return maybe_value;
lrn@chromium.org303ada72010-10-27 09:33:13 +00008377 ASSERT(maybe_value->IsException());
8378 maybe_value = Top::pending_exception();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00008379 Top::clear_pending_exception();
8380 if (caught_exception != NULL) {
8381 *caught_exception = true;
8382 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00008383 return maybe_value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00008384 }
8385 return value;
8386 } else {
8387 return Heap::undefined_value();
8388 }
8389 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008390 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008391 case MAP_TRANSITION:
8392 case CONSTANT_TRANSITION:
8393 case NULL_DESCRIPTOR:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008394 return Heap::undefined_value();
8395 default:
8396 UNREACHABLE();
8397 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008398 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008399 return Heap::undefined_value();
8400}
8401
8402
ager@chromium.org32912102009-01-16 10:38:43 +00008403// Get debugger related details for an object property.
8404// args[0]: object holding property
8405// args[1]: name of the property
8406//
8407// The array returned contains the following information:
8408// 0: Property value
8409// 1: Property details
8410// 2: Property value is exception
8411// 3: Getter function if defined
8412// 4: Setter function if defined
8413// Items 2-4 are only filled if the property has either a getter or a setter
8414// defined through __defineGetter__ and/or __defineSetter__.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008415static MaybeObject* Runtime_DebugGetPropertyDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008416 HandleScope scope;
8417
8418 ASSERT(args.length() == 2);
8419
8420 CONVERT_ARG_CHECKED(JSObject, obj, 0);
8421 CONVERT_ARG_CHECKED(String, name, 1);
8422
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00008423 // Make sure to set the current context to the context before the debugger was
8424 // entered (if the debugger is entered). The reason for switching context here
8425 // is that for some property lookups (accessors and interceptors) callbacks
8426 // into the embedding application can occour, and the embedding application
8427 // could have the assumption that its own global context is the current
8428 // context and not some internal debugger context.
8429 SaveContext save;
8430 if (Debug::InDebugger()) {
8431 Top::set_context(*Debug::debugger_entry()->GetContext());
8432 }
8433
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008434 // Skip the global proxy as it has no properties and always delegates to the
8435 // real global object.
8436 if (obj->IsJSGlobalProxy()) {
8437 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
8438 }
8439
8440
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008441 // Check if the name is trivially convertible to an index and get the element
8442 // if so.
8443 uint32_t index;
8444 if (name->AsArrayIndex(&index)) {
8445 Handle<FixedArray> details = Factory::NewFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008446 Object* element_or_char;
8447 { MaybeObject* maybe_element_or_char =
8448 Runtime::GetElementOrCharAt(obj, index);
8449 if (!maybe_element_or_char->ToObject(&element_or_char)) {
8450 return maybe_element_or_char;
8451 }
8452 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008453 details->set(0, element_or_char);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008454 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
8455 return *Factory::NewJSArrayWithElements(details);
8456 }
8457
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008458 // Find the number of objects making up this.
8459 int length = LocalPrototypeChainLength(*obj);
8460
8461 // Try local lookup on each of the objects.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008462 Handle<JSObject> jsproto = obj;
8463 for (int i = 0; i < length; i++) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008464 LookupResult result;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008465 jsproto->LocalLookup(*name, &result);
8466 if (result.IsProperty()) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008467 // LookupResult is not GC safe as it holds raw object pointers.
8468 // GC can happen later in this code so put the required fields into
8469 // local variables using handles when required for later use.
8470 PropertyType result_type = result.type();
8471 Handle<Object> result_callback_obj;
8472 if (result_type == CALLBACKS) {
8473 result_callback_obj = Handle<Object>(result.GetCallbackObject());
8474 }
8475 Smi* property_details = result.GetPropertyDetails().AsSmi();
8476 // DebugLookupResultValue can cause GC so details from LookupResult needs
8477 // to be copied to handles before this.
8478 bool caught_exception = false;
lrn@chromium.org303ada72010-10-27 09:33:13 +00008479 Object* raw_value;
8480 { MaybeObject* maybe_raw_value =
8481 DebugLookupResultValue(*obj, *name, &result, &caught_exception);
8482 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
8483 }
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008484 Handle<Object> value(raw_value);
8485
8486 // If the callback object is a fixed array then it contains JavaScript
8487 // getter and/or setter.
8488 bool hasJavaScriptAccessors = result_type == CALLBACKS &&
8489 result_callback_obj->IsFixedArray();
8490 Handle<FixedArray> details =
8491 Factory::NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
8492 details->set(0, *value);
8493 details->set(1, property_details);
8494 if (hasJavaScriptAccessors) {
8495 details->set(2,
8496 caught_exception ? Heap::true_value()
8497 : Heap::false_value());
8498 details->set(3, FixedArray::cast(*result_callback_obj)->get(0));
8499 details->set(4, FixedArray::cast(*result_callback_obj)->get(1));
8500 }
8501
8502 return *Factory::NewJSArrayWithElements(details);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008503 }
8504 if (i < length - 1) {
8505 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
8506 }
8507 }
8508
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008509 return Heap::undefined_value();
8510}
8511
8512
lrn@chromium.org303ada72010-10-27 09:33:13 +00008513static MaybeObject* Runtime_DebugGetProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008514 HandleScope scope;
8515
8516 ASSERT(args.length() == 2);
8517
8518 CONVERT_ARG_CHECKED(JSObject, obj, 0);
8519 CONVERT_ARG_CHECKED(String, name, 1);
8520
8521 LookupResult result;
8522 obj->Lookup(*name, &result);
8523 if (result.IsProperty()) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +00008524 return DebugLookupResultValue(*obj, *name, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008525 }
8526 return Heap::undefined_value();
8527}
8528
8529
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008530// Return the property type calculated from the property details.
8531// args[0]: smi with property details.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008532static MaybeObject* Runtime_DebugPropertyTypeFromDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008533 ASSERT(args.length() == 1);
8534 CONVERT_CHECKED(Smi, details, args[0]);
8535 PropertyType type = PropertyDetails(details).type();
8536 return Smi::FromInt(static_cast<int>(type));
8537}
8538
8539
8540// Return the property attribute calculated from the property details.
8541// args[0]: smi with property details.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008542static MaybeObject* Runtime_DebugPropertyAttributesFromDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008543 ASSERT(args.length() == 1);
8544 CONVERT_CHECKED(Smi, details, args[0]);
8545 PropertyAttributes attributes = PropertyDetails(details).attributes();
8546 return Smi::FromInt(static_cast<int>(attributes));
8547}
8548
8549
8550// Return the property insertion index calculated from the property details.
8551// args[0]: smi with property details.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008552static MaybeObject* Runtime_DebugPropertyIndexFromDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008553 ASSERT(args.length() == 1);
8554 CONVERT_CHECKED(Smi, details, args[0]);
8555 int index = PropertyDetails(details).index();
8556 return Smi::FromInt(index);
8557}
8558
8559
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008560// Return property value from named interceptor.
8561// args[0]: object
8562// args[1]: property name
lrn@chromium.org303ada72010-10-27 09:33:13 +00008563static MaybeObject* Runtime_DebugNamedInterceptorPropertyValue(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008564 HandleScope scope;
8565 ASSERT(args.length() == 2);
8566 CONVERT_ARG_CHECKED(JSObject, obj, 0);
8567 RUNTIME_ASSERT(obj->HasNamedInterceptor());
8568 CONVERT_ARG_CHECKED(String, name, 1);
8569
8570 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008571 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008572}
8573
8574
8575// Return element value from indexed interceptor.
8576// args[0]: object
8577// args[1]: index
lrn@chromium.org303ada72010-10-27 09:33:13 +00008578static MaybeObject* Runtime_DebugIndexedInterceptorElementValue(
8579 Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008580 HandleScope scope;
8581 ASSERT(args.length() == 2);
8582 CONVERT_ARG_CHECKED(JSObject, obj, 0);
8583 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
8584 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
8585
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008586 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008587}
8588
8589
lrn@chromium.org303ada72010-10-27 09:33:13 +00008590static MaybeObject* Runtime_CheckExecutionState(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008591 ASSERT(args.length() >= 1);
8592 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +00008593 // Check that the break id is valid.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00008594 if (Debug::break_id() == 0 || break_id != Debug::break_id()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008595 return Top::Throw(Heap::illegal_execution_state_symbol());
8596 }
8597
8598 return Heap::true_value();
8599}
8600
8601
lrn@chromium.org303ada72010-10-27 09:33:13 +00008602static MaybeObject* Runtime_GetFrameCount(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008603 HandleScope scope;
8604 ASSERT(args.length() == 1);
8605
8606 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008607 Object* result;
8608 { MaybeObject* maybe_result = Runtime_CheckExecutionState(args);
8609 if (!maybe_result->ToObject(&result)) return maybe_result;
8610 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008611
8612 // Count all frames which are relevant to debugging stack trace.
8613 int n = 0;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00008614 StackFrame::Id id = Debug::break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00008615 if (id == StackFrame::NO_ID) {
8616 // If there is no JavaScript stack frame count is 0.
8617 return Smi::FromInt(0);
8618 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008619 for (JavaScriptFrameIterator it(id); !it.done(); it.Advance()) n++;
8620 return Smi::FromInt(n);
8621}
8622
8623
8624static const int kFrameDetailsFrameIdIndex = 0;
8625static const int kFrameDetailsReceiverIndex = 1;
8626static const int kFrameDetailsFunctionIndex = 2;
8627static const int kFrameDetailsArgumentCountIndex = 3;
8628static const int kFrameDetailsLocalCountIndex = 4;
8629static const int kFrameDetailsSourcePositionIndex = 5;
8630static const int kFrameDetailsConstructCallIndex = 6;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008631static const int kFrameDetailsAtReturnIndex = 7;
8632static const int kFrameDetailsDebuggerFrameIndex = 8;
8633static const int kFrameDetailsFirstDynamicIndex = 9;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008634
8635// Return an array with frame details
8636// args[0]: number: break id
8637// args[1]: number: frame index
8638//
8639// The array returned contains the following information:
8640// 0: Frame id
8641// 1: Receiver
8642// 2: Function
8643// 3: Argument count
8644// 4: Local count
8645// 5: Source position
8646// 6: Constructor call
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008647// 7: Is at return
8648// 8: Debugger frame
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008649// Arguments name, value
8650// Locals name, value
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008651// Return value if any
lrn@chromium.org303ada72010-10-27 09:33:13 +00008652static MaybeObject* Runtime_GetFrameDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008653 HandleScope scope;
8654 ASSERT(args.length() == 2);
8655
8656 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008657 Object* check;
8658 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
8659 if (!maybe_check->ToObject(&check)) return maybe_check;
8660 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008661 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
8662
8663 // Find the relevant frame with the requested index.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00008664 StackFrame::Id id = Debug::break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00008665 if (id == StackFrame::NO_ID) {
8666 // If there are no JavaScript stack frames return undefined.
8667 return Heap::undefined_value();
8668 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008669 int count = 0;
8670 JavaScriptFrameIterator it(id);
8671 for (; !it.done(); it.Advance()) {
8672 if (count == index) break;
8673 count++;
8674 }
8675 if (it.done()) return Heap::undefined_value();
8676
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008677 bool is_optimized_frame =
8678 it.frame()->code()->kind() == Code::OPTIMIZED_FUNCTION;
8679
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008680 // Traverse the saved contexts chain to find the active context for the
8681 // selected frame.
8682 SaveContext* save = Top::save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008683 while (save != NULL && !save->below(it.frame())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008684 save = save->prev();
8685 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008686 ASSERT(save != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008687
8688 // Get the frame id.
8689 Handle<Object> frame_id(WrapFrameId(it.frame()->id()));
8690
8691 // Find source position.
kasperl@chromium.org061ef742009-02-27 12:16:20 +00008692 int position = it.frame()->code()->SourcePosition(it.frame()->pc());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008693
8694 // Check for constructor frame.
8695 bool constructor = it.frame()->IsConstructor();
8696
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00008697 // Get scope info and read from it for local variable information.
8698 Handle<JSFunction> function(JSFunction::cast(it.frame()->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +00008699 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00008700 ScopeInfo<> info(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008701
8702 // Get the context.
8703 Handle<Context> context(Context::cast(it.frame()->context()));
8704
8705 // Get the locals names and values into a temporary array.
8706 //
8707 // TODO(1240907): Hide compiler-introduced stack variables
8708 // (e.g. .result)? For users of the debugger, they will probably be
8709 // confusing.
8710 Handle<FixedArray> locals = Factory::NewFixedArray(info.NumberOfLocals() * 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008711
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008712 // Fill in the names of the locals.
8713 for (int i = 0; i < info.NumberOfLocals(); i++) {
8714 locals->set(i * 2, *info.LocalName(i));
8715 }
8716
8717 // Fill in the values of the locals.
8718 for (int i = 0; i < info.NumberOfLocals(); i++) {
8719 if (is_optimized_frame) {
8720 // If we are inspecting an optimized frame use undefined as the
8721 // value for all locals.
8722 //
8723 // TODO(3141533): We should be able to get the correct values
8724 // for locals in optimized frames.
8725 locals->set(i * 2 + 1, Heap::undefined_value());
8726 } else if (i < info.number_of_stack_slots()) {
8727 // Get the value from the stack.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008728 locals->set(i * 2 + 1, it.frame()->GetExpression(i));
8729 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008730 // Traverse the context chain to the function context as all local
8731 // variables stored in the context will be on the function context.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008732 Handle<String> name = info.LocalName(i);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008733 while (!context->is_function_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008734 context = Handle<Context>(context->previous());
8735 }
8736 ASSERT(context->is_function_context());
8737 locals->set(i * 2 + 1,
ager@chromium.orgb5737492010-07-15 09:29:43 +00008738 context->get(scope_info->ContextSlotIndex(*name, NULL)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008739 }
8740 }
8741
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008742 // Check whether this frame is positioned at return. If not top
8743 // frame or if the frame is optimized it cannot be at a return.
8744 bool at_return = false;
8745 if (!is_optimized_frame && index == 0) {
8746 at_return = Debug::IsBreakAtReturn(it.frame());
8747 }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008748
8749 // If positioned just before return find the value to be returned and add it
8750 // to the frame information.
8751 Handle<Object> return_value = Factory::undefined_value();
8752 if (at_return) {
8753 StackFrameIterator it2;
8754 Address internal_frame_sp = NULL;
8755 while (!it2.done()) {
8756 if (it2.frame()->is_internal()) {
8757 internal_frame_sp = it2.frame()->sp();
8758 } else {
8759 if (it2.frame()->is_java_script()) {
8760 if (it2.frame()->id() == it.frame()->id()) {
8761 // The internal frame just before the JavaScript frame contains the
8762 // value to return on top. A debug break at return will create an
8763 // internal frame to store the return value (eax/rax/r0) before
8764 // entering the debug break exit frame.
8765 if (internal_frame_sp != NULL) {
8766 return_value =
8767 Handle<Object>(Memory::Object_at(internal_frame_sp));
8768 break;
8769 }
8770 }
8771 }
8772
8773 // Indicate that the previous frame was not an internal frame.
8774 internal_frame_sp = NULL;
8775 }
8776 it2.Advance();
8777 }
8778 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008779
8780 // Now advance to the arguments adapter frame (if any). It contains all
8781 // the provided parameters whereas the function frame always have the number
8782 // of arguments matching the functions parameters. The rest of the
8783 // information (except for what is collected above) is the same.
8784 it.AdvanceToArgumentsFrame();
8785
8786 // Find the number of arguments to fill. At least fill the number of
8787 // parameters for the function and fill more if more parameters are provided.
8788 int argument_count = info.number_of_parameters();
8789 if (argument_count < it.frame()->GetProvidedParametersCount()) {
8790 argument_count = it.frame()->GetProvidedParametersCount();
8791 }
8792
8793 // Calculate the size of the result.
8794 int details_size = kFrameDetailsFirstDynamicIndex +
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008795 2 * (argument_count + info.NumberOfLocals()) +
8796 (at_return ? 1 : 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008797 Handle<FixedArray> details = Factory::NewFixedArray(details_size);
8798
8799 // Add the frame id.
8800 details->set(kFrameDetailsFrameIdIndex, *frame_id);
8801
8802 // Add the function (same as in function frame).
8803 details->set(kFrameDetailsFunctionIndex, it.frame()->function());
8804
8805 // Add the arguments count.
8806 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
8807
8808 // Add the locals count
8809 details->set(kFrameDetailsLocalCountIndex,
8810 Smi::FromInt(info.NumberOfLocals()));
8811
8812 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +00008813 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008814 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
8815 } else {
8816 details->set(kFrameDetailsSourcePositionIndex, Heap::undefined_value());
8817 }
8818
8819 // Add the constructor information.
8820 details->set(kFrameDetailsConstructCallIndex, Heap::ToBoolean(constructor));
8821
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008822 // Add the at return information.
8823 details->set(kFrameDetailsAtReturnIndex, Heap::ToBoolean(at_return));
8824
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008825 // Add information on whether this frame is invoked in the debugger context.
8826 details->set(kFrameDetailsDebuggerFrameIndex,
8827 Heap::ToBoolean(*save->context() == *Debug::debug_context()));
8828
8829 // Fill the dynamic part.
8830 int details_index = kFrameDetailsFirstDynamicIndex;
8831
8832 // Add arguments name and value.
8833 for (int i = 0; i < argument_count; i++) {
8834 // Name of the argument.
8835 if (i < info.number_of_parameters()) {
8836 details->set(details_index++, *info.parameter_name(i));
8837 } else {
8838 details->set(details_index++, Heap::undefined_value());
8839 }
8840
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008841 // Parameter value. If we are inspecting an optimized frame, use
8842 // undefined as the value.
8843 //
8844 // TODO(3141533): We should be able to get the actual parameter
8845 // value for optimized frames.
8846 if (!is_optimized_frame &&
8847 (i < it.frame()->GetProvidedParametersCount())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008848 details->set(details_index++, it.frame()->GetParameter(i));
8849 } else {
8850 details->set(details_index++, Heap::undefined_value());
8851 }
8852 }
8853
8854 // Add locals name and value from the temporary copy from the function frame.
8855 for (int i = 0; i < info.NumberOfLocals() * 2; i++) {
8856 details->set(details_index++, locals->get(i));
8857 }
8858
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008859 // Add the value being returned.
8860 if (at_return) {
8861 details->set(details_index++, *return_value);
8862 }
8863
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008864 // Add the receiver (same as in function frame).
8865 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
8866 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
8867 Handle<Object> receiver(it.frame()->receiver());
8868 if (!receiver->IsJSObject()) {
8869 // If the receiver is NOT a JSObject we have hit an optimization
8870 // where a value object is not converted into a wrapped JS objects.
8871 // To hide this optimization from the debugger, we wrap the receiver
8872 // by creating correct wrapper object based on the calling frame's
8873 // global context.
8874 it.Advance();
8875 Handle<Context> calling_frames_global_context(
8876 Context::cast(Context::cast(it.frame()->context())->global_context()));
8877 receiver = Factory::ToObject(receiver, calling_frames_global_context);
8878 }
8879 details->set(kFrameDetailsReceiverIndex, *receiver);
8880
8881 ASSERT_EQ(details_size, details_index);
8882 return *Factory::NewJSArrayWithElements(details);
8883}
8884
8885
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008886// Copy all the context locals into an object used to materialize a scope.
ager@chromium.orgb5737492010-07-15 09:29:43 +00008887static void CopyContextLocalsToScopeObject(
8888 Handle<SerializedScopeInfo> serialized_scope_info,
8889 ScopeInfo<>& scope_info,
8890 Handle<Context> context,
8891 Handle<JSObject> scope_object) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008892 // Fill all context locals to the context extension.
8893 for (int i = Context::MIN_CONTEXT_SLOTS;
8894 i < scope_info.number_of_context_slots();
8895 i++) {
ager@chromium.orgb5737492010-07-15 09:29:43 +00008896 int context_index = serialized_scope_info->ContextSlotIndex(
8897 *scope_info.context_slot_name(i), NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008898
8899 // Don't include the arguments shadow (.arguments) context variable.
8900 if (*scope_info.context_slot_name(i) != Heap::arguments_shadow_symbol()) {
8901 SetProperty(scope_object,
8902 scope_info.context_slot_name(i),
8903 Handle<Object>(context->get(context_index)), NONE);
8904 }
8905 }
8906}
8907
8908
8909// Create a plain JSObject which materializes the local scope for the specified
8910// frame.
8911static Handle<JSObject> MaterializeLocalScope(JavaScriptFrame* frame) {
8912 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00008913 Handle<SharedFunctionInfo> shared(function->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +00008914 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
8915 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008916
8917 // Allocate and initialize a JSObject with all the arguments, stack locals
8918 // heap locals and extension properties of the debugged function.
8919 Handle<JSObject> local_scope = Factory::NewJSObject(Top::object_function());
8920
8921 // First fill all parameters.
8922 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
8923 SetProperty(local_scope,
8924 scope_info.parameter_name(i),
8925 Handle<Object>(frame->GetParameter(i)), NONE);
8926 }
8927
8928 // Second fill all stack locals.
8929 for (int i = 0; i < scope_info.number_of_stack_slots(); i++) {
8930 SetProperty(local_scope,
8931 scope_info.stack_slot_name(i),
8932 Handle<Object>(frame->GetExpression(i)), NONE);
8933 }
8934
8935 // Third fill all context locals.
8936 Handle<Context> frame_context(Context::cast(frame->context()));
8937 Handle<Context> function_context(frame_context->fcontext());
ager@chromium.orgb5737492010-07-15 09:29:43 +00008938 CopyContextLocalsToScopeObject(serialized_scope_info, scope_info,
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008939 function_context, local_scope);
8940
8941 // Finally copy any properties from the function context extension. This will
8942 // be variables introduced by eval.
8943 if (function_context->closure() == *function) {
8944 if (function_context->has_extension() &&
8945 !function_context->IsGlobalContext()) {
8946 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008947 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008948 for (int i = 0; i < keys->length(); i++) {
8949 // Names of variables introduced by eval are strings.
8950 ASSERT(keys->get(i)->IsString());
8951 Handle<String> key(String::cast(keys->get(i)));
8952 SetProperty(local_scope, key, GetProperty(ext, key), NONE);
8953 }
8954 }
8955 }
8956 return local_scope;
8957}
8958
8959
8960// Create a plain JSObject which materializes the closure content for the
8961// context.
8962static Handle<JSObject> MaterializeClosure(Handle<Context> context) {
8963 ASSERT(context->is_function_context());
8964
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00008965 Handle<SharedFunctionInfo> shared(context->closure()->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +00008966 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
8967 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008968
8969 // Allocate and initialize a JSObject with all the content of theis function
8970 // closure.
8971 Handle<JSObject> closure_scope = Factory::NewJSObject(Top::object_function());
8972
8973 // Check whether the arguments shadow object exists.
8974 int arguments_shadow_index =
ager@chromium.orgb5737492010-07-15 09:29:43 +00008975 shared->scope_info()->ContextSlotIndex(Heap::arguments_shadow_symbol(),
8976 NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008977 if (arguments_shadow_index >= 0) {
8978 // In this case all the arguments are available in the arguments shadow
8979 // object.
8980 Handle<JSObject> arguments_shadow(
8981 JSObject::cast(context->get(arguments_shadow_index)));
8982 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008983 // We don't expect exception-throwing getters on the arguments shadow.
8984 Object* element = arguments_shadow->GetElement(i)->ToObjectUnchecked();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008985 SetProperty(closure_scope,
8986 scope_info.parameter_name(i),
lrn@chromium.org303ada72010-10-27 09:33:13 +00008987 Handle<Object>(element),
8988 NONE);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008989 }
8990 }
8991
8992 // Fill all context locals to the context extension.
ager@chromium.orgb5737492010-07-15 09:29:43 +00008993 CopyContextLocalsToScopeObject(serialized_scope_info, scope_info,
8994 context, closure_scope);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008995
8996 // Finally copy any properties from the function context extension. This will
8997 // be variables introduced by eval.
8998 if (context->has_extension()) {
8999 Handle<JSObject> ext(JSObject::cast(context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009000 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009001 for (int i = 0; i < keys->length(); i++) {
9002 // Names of variables introduced by eval are strings.
9003 ASSERT(keys->get(i)->IsString());
9004 Handle<String> key(String::cast(keys->get(i)));
9005 SetProperty(closure_scope, key, GetProperty(ext, key), NONE);
9006 }
9007 }
9008
9009 return closure_scope;
9010}
9011
9012
9013// Iterate over the actual scopes visible from a stack frame. All scopes are
9014// backed by an actual context except the local scope, which is inserted
9015// "artifically" in the context chain.
9016class ScopeIterator {
9017 public:
9018 enum ScopeType {
9019 ScopeTypeGlobal = 0,
9020 ScopeTypeLocal,
9021 ScopeTypeWith,
ager@chromium.orga1645e22009-09-09 19:27:10 +00009022 ScopeTypeClosure,
9023 // Every catch block contains an implicit with block (its parameter is
9024 // a JSContextExtensionObject) that extends current scope with a variable
9025 // holding exception object. Such with blocks are treated as scopes of their
9026 // own type.
9027 ScopeTypeCatch
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009028 };
9029
9030 explicit ScopeIterator(JavaScriptFrame* frame)
9031 : frame_(frame),
9032 function_(JSFunction::cast(frame->function())),
9033 context_(Context::cast(frame->context())),
9034 local_done_(false),
9035 at_local_(false) {
9036
9037 // Check whether the first scope is actually a local scope.
9038 if (context_->IsGlobalContext()) {
9039 // If there is a stack slot for .result then this local scope has been
9040 // created for evaluating top level code and it is not a real local scope.
9041 // Checking for the existence of .result seems fragile, but the scope info
9042 // saved with the code object does not otherwise have that information.
ager@chromium.orgb5737492010-07-15 09:29:43 +00009043 int index = function_->shared()->scope_info()->
9044 StackSlotIndex(Heap::result_symbol());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009045 at_local_ = index < 0;
9046 } else if (context_->is_function_context()) {
9047 at_local_ = true;
9048 }
9049 }
9050
9051 // More scopes?
9052 bool Done() { return context_.is_null(); }
9053
9054 // Move to the next scope.
9055 void Next() {
9056 // If at a local scope mark the local scope as passed.
9057 if (at_local_) {
9058 at_local_ = false;
9059 local_done_ = true;
9060
9061 // If the current context is not associated with the local scope the
9062 // current context is the next real scope, so don't move to the next
9063 // context in this case.
9064 if (context_->closure() != *function_) {
9065 return;
9066 }
9067 }
9068
9069 // The global scope is always the last in the chain.
9070 if (context_->IsGlobalContext()) {
9071 context_ = Handle<Context>();
9072 return;
9073 }
9074
9075 // Move to the next context.
9076 if (context_->is_function_context()) {
9077 context_ = Handle<Context>(Context::cast(context_->closure()->context()));
9078 } else {
9079 context_ = Handle<Context>(context_->previous());
9080 }
9081
9082 // If passing the local scope indicate that the current scope is now the
9083 // local scope.
9084 if (!local_done_ &&
9085 (context_->IsGlobalContext() || (context_->is_function_context()))) {
9086 at_local_ = true;
9087 }
9088 }
9089
9090 // Return the type of the current scope.
9091 int Type() {
9092 if (at_local_) {
9093 return ScopeTypeLocal;
9094 }
9095 if (context_->IsGlobalContext()) {
9096 ASSERT(context_->global()->IsGlobalObject());
9097 return ScopeTypeGlobal;
9098 }
9099 if (context_->is_function_context()) {
9100 return ScopeTypeClosure;
9101 }
9102 ASSERT(context_->has_extension());
ager@chromium.orga1645e22009-09-09 19:27:10 +00009103 // Current scope is either an explicit with statement or a with statement
9104 // implicitely generated for a catch block.
9105 // If the extension object here is a JSContextExtensionObject then
9106 // current with statement is one frome a catch block otherwise it's a
9107 // regular with statement.
9108 if (context_->extension()->IsJSContextExtensionObject()) {
9109 return ScopeTypeCatch;
9110 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009111 return ScopeTypeWith;
9112 }
9113
9114 // Return the JavaScript object with the content of the current scope.
9115 Handle<JSObject> ScopeObject() {
9116 switch (Type()) {
9117 case ScopeIterator::ScopeTypeGlobal:
9118 return Handle<JSObject>(CurrentContext()->global());
9119 break;
9120 case ScopeIterator::ScopeTypeLocal:
9121 // Materialize the content of the local scope into a JSObject.
9122 return MaterializeLocalScope(frame_);
9123 break;
9124 case ScopeIterator::ScopeTypeWith:
ager@chromium.orga1645e22009-09-09 19:27:10 +00009125 case ScopeIterator::ScopeTypeCatch:
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009126 // Return the with object.
9127 return Handle<JSObject>(CurrentContext()->extension());
9128 break;
9129 case ScopeIterator::ScopeTypeClosure:
9130 // Materialize the content of the closure scope into a JSObject.
9131 return MaterializeClosure(CurrentContext());
9132 break;
9133 }
9134 UNREACHABLE();
9135 return Handle<JSObject>();
9136 }
9137
9138 // Return the context for this scope. For the local context there might not
9139 // be an actual context.
9140 Handle<Context> CurrentContext() {
9141 if (at_local_ && context_->closure() != *function_) {
9142 return Handle<Context>();
9143 }
9144 return context_;
9145 }
9146
9147#ifdef DEBUG
9148 // Debug print of the content of the current scope.
9149 void DebugPrint() {
9150 switch (Type()) {
9151 case ScopeIterator::ScopeTypeGlobal:
9152 PrintF("Global:\n");
9153 CurrentContext()->Print();
9154 break;
9155
9156 case ScopeIterator::ScopeTypeLocal: {
9157 PrintF("Local:\n");
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009158 ScopeInfo<> scope_info(function_->shared()->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009159 scope_info.Print();
9160 if (!CurrentContext().is_null()) {
9161 CurrentContext()->Print();
9162 if (CurrentContext()->has_extension()) {
9163 Handle<JSObject> extension =
9164 Handle<JSObject>(CurrentContext()->extension());
9165 if (extension->IsJSContextExtensionObject()) {
9166 extension->Print();
9167 }
9168 }
9169 }
9170 break;
9171 }
9172
9173 case ScopeIterator::ScopeTypeWith: {
9174 PrintF("With:\n");
9175 Handle<JSObject> extension =
9176 Handle<JSObject>(CurrentContext()->extension());
9177 extension->Print();
9178 break;
9179 }
9180
ager@chromium.orga1645e22009-09-09 19:27:10 +00009181 case ScopeIterator::ScopeTypeCatch: {
9182 PrintF("Catch:\n");
9183 Handle<JSObject> extension =
9184 Handle<JSObject>(CurrentContext()->extension());
9185 extension->Print();
9186 break;
9187 }
9188
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009189 case ScopeIterator::ScopeTypeClosure: {
9190 PrintF("Closure:\n");
9191 CurrentContext()->Print();
9192 if (CurrentContext()->has_extension()) {
9193 Handle<JSObject> extension =
9194 Handle<JSObject>(CurrentContext()->extension());
9195 if (extension->IsJSContextExtensionObject()) {
9196 extension->Print();
9197 }
9198 }
9199 break;
9200 }
9201
9202 default:
9203 UNREACHABLE();
9204 }
9205 PrintF("\n");
9206 }
9207#endif
9208
9209 private:
9210 JavaScriptFrame* frame_;
9211 Handle<JSFunction> function_;
9212 Handle<Context> context_;
9213 bool local_done_;
9214 bool at_local_;
9215
9216 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
9217};
9218
9219
lrn@chromium.org303ada72010-10-27 09:33:13 +00009220static MaybeObject* Runtime_GetScopeCount(Arguments args) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009221 HandleScope scope;
9222 ASSERT(args.length() == 2);
9223
9224 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009225 Object* check;
9226 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
9227 if (!maybe_check->ToObject(&check)) return maybe_check;
9228 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009229 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
9230
9231 // Get the frame where the debugging is performed.
9232 StackFrame::Id id = UnwrapFrameId(wrapped_id);
9233 JavaScriptFrameIterator it(id);
9234 JavaScriptFrame* frame = it.frame();
9235
9236 // Count the visible scopes.
9237 int n = 0;
9238 for (ScopeIterator it(frame); !it.Done(); it.Next()) {
9239 n++;
9240 }
9241
9242 return Smi::FromInt(n);
9243}
9244
9245
9246static const int kScopeDetailsTypeIndex = 0;
9247static const int kScopeDetailsObjectIndex = 1;
9248static const int kScopeDetailsSize = 2;
9249
9250// Return an array with scope details
9251// args[0]: number: break id
9252// args[1]: number: frame index
9253// args[2]: number: scope index
9254//
9255// The array returned contains the following information:
9256// 0: Scope type
9257// 1: Scope object
lrn@chromium.org303ada72010-10-27 09:33:13 +00009258static MaybeObject* Runtime_GetScopeDetails(Arguments args) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009259 HandleScope scope;
9260 ASSERT(args.length() == 3);
9261
9262 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009263 Object* check;
9264 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
9265 if (!maybe_check->ToObject(&check)) return maybe_check;
9266 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009267 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
9268 CONVERT_NUMBER_CHECKED(int, index, Int32, args[2]);
9269
9270 // Get the frame where the debugging is performed.
9271 StackFrame::Id id = UnwrapFrameId(wrapped_id);
9272 JavaScriptFrameIterator frame_it(id);
9273 JavaScriptFrame* frame = frame_it.frame();
9274
9275 // Find the requested scope.
9276 int n = 0;
9277 ScopeIterator it(frame);
9278 for (; !it.Done() && n < index; it.Next()) {
9279 n++;
9280 }
9281 if (it.Done()) {
9282 return Heap::undefined_value();
9283 }
9284
9285 // Calculate the size of the result.
9286 int details_size = kScopeDetailsSize;
9287 Handle<FixedArray> details = Factory::NewFixedArray(details_size);
9288
9289 // Fill in scope details.
9290 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00009291 Handle<JSObject> scope_object = it.ScopeObject();
9292 details->set(kScopeDetailsObjectIndex, *scope_object);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009293
9294 return *Factory::NewJSArrayWithElements(details);
9295}
9296
9297
lrn@chromium.org303ada72010-10-27 09:33:13 +00009298static MaybeObject* Runtime_DebugPrintScopes(Arguments args) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009299 HandleScope scope;
9300 ASSERT(args.length() == 0);
9301
9302#ifdef DEBUG
9303 // Print the scopes for the top frame.
9304 StackFrameLocator locator;
9305 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
9306 for (ScopeIterator it(frame); !it.Done(); it.Next()) {
9307 it.DebugPrint();
9308 }
9309#endif
9310 return Heap::undefined_value();
9311}
9312
9313
lrn@chromium.org303ada72010-10-27 09:33:13 +00009314static MaybeObject* Runtime_GetThreadCount(Arguments args) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009315 HandleScope scope;
9316 ASSERT(args.length() == 1);
9317
9318 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009319 Object* result;
9320 { MaybeObject* maybe_result = Runtime_CheckExecutionState(args);
9321 if (!maybe_result->ToObject(&result)) return maybe_result;
9322 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009323
9324 // Count all archived V8 threads.
9325 int n = 0;
9326 for (ThreadState* thread = ThreadState::FirstInUse();
9327 thread != NULL;
9328 thread = thread->Next()) {
9329 n++;
9330 }
9331
9332 // Total number of threads is current thread and archived threads.
9333 return Smi::FromInt(n + 1);
9334}
9335
9336
9337static const int kThreadDetailsCurrentThreadIndex = 0;
9338static const int kThreadDetailsThreadIdIndex = 1;
9339static const int kThreadDetailsSize = 2;
9340
9341// Return an array with thread details
9342// args[0]: number: break id
9343// args[1]: number: thread index
9344//
9345// The array returned contains the following information:
9346// 0: Is current thread?
9347// 1: Thread id
lrn@chromium.org303ada72010-10-27 09:33:13 +00009348static MaybeObject* Runtime_GetThreadDetails(Arguments args) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009349 HandleScope scope;
9350 ASSERT(args.length() == 2);
9351
9352 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009353 Object* check;
9354 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
9355 if (!maybe_check->ToObject(&check)) return maybe_check;
9356 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009357 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
9358
9359 // Allocate array for result.
9360 Handle<FixedArray> details = Factory::NewFixedArray(kThreadDetailsSize);
9361
9362 // Thread index 0 is current thread.
9363 if (index == 0) {
9364 // Fill the details.
9365 details->set(kThreadDetailsCurrentThreadIndex, Heap::true_value());
9366 details->set(kThreadDetailsThreadIdIndex,
9367 Smi::FromInt(ThreadManager::CurrentId()));
9368 } else {
9369 // Find the thread with the requested index.
9370 int n = 1;
9371 ThreadState* thread = ThreadState::FirstInUse();
9372 while (index != n && thread != NULL) {
9373 thread = thread->Next();
9374 n++;
9375 }
9376 if (thread == NULL) {
9377 return Heap::undefined_value();
9378 }
9379
9380 // Fill the details.
9381 details->set(kThreadDetailsCurrentThreadIndex, Heap::false_value());
9382 details->set(kThreadDetailsThreadIdIndex, Smi::FromInt(thread->id()));
9383 }
9384
9385 // Convert to JS array and return.
9386 return *Factory::NewJSArrayWithElements(details);
9387}
9388
9389
whesse@chromium.orge90029b2010-08-02 11:52:17 +00009390// Sets the disable break state
9391// args[0]: disable break state
lrn@chromium.org303ada72010-10-27 09:33:13 +00009392static MaybeObject* Runtime_SetDisableBreak(Arguments args) {
whesse@chromium.orge90029b2010-08-02 11:52:17 +00009393 HandleScope scope;
9394 ASSERT(args.length() == 1);
9395 CONVERT_BOOLEAN_CHECKED(disable_break, args[0]);
9396 Debug::set_disable_break(disable_break);
9397 return Heap::undefined_value();
9398}
9399
9400
lrn@chromium.org303ada72010-10-27 09:33:13 +00009401static MaybeObject* Runtime_GetBreakLocations(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009402 HandleScope scope;
9403 ASSERT(args.length() == 1);
9404
ager@chromium.org5aa501c2009-06-23 07:57:28 +00009405 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
9406 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009407 // Find the number of break points
9408 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
9409 if (break_locations->IsUndefined()) return Heap::undefined_value();
9410 // Return array as JS array
9411 return *Factory::NewJSArrayWithElements(
9412 Handle<FixedArray>::cast(break_locations));
9413}
9414
9415
9416// Set a break point in a function
9417// args[0]: function
9418// args[1]: number: break source position (within the function source)
9419// args[2]: number: break point object
lrn@chromium.org303ada72010-10-27 09:33:13 +00009420static MaybeObject* Runtime_SetFunctionBreakPoint(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009421 HandleScope scope;
9422 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00009423 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
9424 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009425 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
9426 RUNTIME_ASSERT(source_position >= 0);
9427 Handle<Object> break_point_object_arg = args.at<Object>(2);
9428
9429 // Set break point.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00009430 Debug::SetBreakPoint(shared, break_point_object_arg, &source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009431
lrn@chromium.org32d961d2010-06-30 09:09:34 +00009432 return Smi::FromInt(source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009433}
9434
9435
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00009436Object* Runtime::FindSharedFunctionInfoInScript(Handle<Script> script,
9437 int position) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009438 // Iterate the heap looking for SharedFunctionInfo generated from the
9439 // script. The inner most SharedFunctionInfo containing the source position
9440 // for the requested break point is found.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009441 // NOTE: This might require several heap iterations. If the SharedFunctionInfo
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009442 // which is found is not compiled it is compiled and the heap is iterated
9443 // again as the compilation might create inner functions from the newly
9444 // compiled function and the actual requested break point might be in one of
9445 // these functions.
9446 bool done = false;
9447 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +00009448 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009449 Handle<SharedFunctionInfo> target;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009450 while (!done) {
9451 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009452 for (HeapObject* obj = iterator.next();
9453 obj != NULL; obj = iterator.next()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009454 if (obj->IsSharedFunctionInfo()) {
9455 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
9456 if (shared->script() == *script) {
9457 // If the SharedFunctionInfo found has the requested script data and
9458 // contains the source position it is a candidate.
9459 int start_position = shared->function_token_position();
ager@chromium.org236ad962008-09-25 09:45:57 +00009460 if (start_position == RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009461 start_position = shared->start_position();
9462 }
9463 if (start_position <= position &&
9464 position <= shared->end_position()) {
ager@chromium.org32912102009-01-16 10:38:43 +00009465 // If there is no candidate or this function is within the current
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009466 // candidate this is the new candidate.
9467 if (target.is_null()) {
9468 target_start_position = start_position;
9469 target = shared;
9470 } else {
ager@chromium.orga1645e22009-09-09 19:27:10 +00009471 if (target_start_position == start_position &&
9472 shared->end_position() == target->end_position()) {
9473 // If a top-level function contain only one function
9474 // declartion the source for the top-level and the function is
9475 // the same. In that case prefer the non top-level function.
9476 if (!shared->is_toplevel()) {
9477 target_start_position = start_position;
9478 target = shared;
9479 }
9480 } else if (target_start_position <= start_position &&
9481 shared->end_position() <= target->end_position()) {
9482 // This containment check includes equality as a function inside
9483 // a top-level function can share either start or end position
9484 // with the top-level function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009485 target_start_position = start_position;
9486 target = shared;
9487 }
9488 }
9489 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009490 }
9491 }
9492 }
9493
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009494 if (target.is_null()) {
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00009495 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009496 }
9497
9498 // If the candidate found is compiled we are done. NOTE: when lazy
9499 // compilation of inner functions is introduced some additional checking
9500 // needs to be done here to compile inner functions.
9501 done = target->is_compiled();
9502 if (!done) {
9503 // If the candidate is not compiled compile it to reveal any inner
9504 // functions which might contain the requested source position.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009505 CompileLazyShared(target, KEEP_EXCEPTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009506 }
9507 }
9508
9509 return *target;
9510}
9511
9512
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00009513// Changes the state of a break point in a script and returns source position
9514// where break point was set. NOTE: Regarding performance see the NOTE for
9515// GetScriptFromScriptData.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009516// args[0]: script to set break point in
9517// args[1]: number: break source position (within the script source)
9518// args[2]: number: break point object
lrn@chromium.org303ada72010-10-27 09:33:13 +00009519static MaybeObject* Runtime_SetScriptBreakPoint(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009520 HandleScope scope;
9521 ASSERT(args.length() == 3);
9522 CONVERT_ARG_CHECKED(JSValue, wrapper, 0);
9523 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
9524 RUNTIME_ASSERT(source_position >= 0);
9525 Handle<Object> break_point_object_arg = args.at<Object>(2);
9526
9527 // Get the script from the script wrapper.
9528 RUNTIME_ASSERT(wrapper->value()->IsScript());
9529 Handle<Script> script(Script::cast(wrapper->value()));
9530
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00009531 Object* result = Runtime::FindSharedFunctionInfoInScript(
9532 script, source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009533 if (!result->IsUndefined()) {
9534 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
9535 // Find position within function. The script position might be before the
9536 // source position of the first function.
9537 int position;
9538 if (shared->start_position() > source_position) {
9539 position = 0;
9540 } else {
9541 position = source_position - shared->start_position();
9542 }
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00009543 Debug::SetBreakPoint(shared, break_point_object_arg, &position);
9544 position += shared->start_position();
9545 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009546 }
9547 return Heap::undefined_value();
9548}
9549
9550
9551// Clear a break point
9552// args[0]: number: break point object
lrn@chromium.org303ada72010-10-27 09:33:13 +00009553static MaybeObject* Runtime_ClearBreakPoint(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009554 HandleScope scope;
9555 ASSERT(args.length() == 1);
9556 Handle<Object> break_point_object_arg = args.at<Object>(0);
9557
9558 // Clear break point.
9559 Debug::ClearBreakPoint(break_point_object_arg);
9560
9561 return Heap::undefined_value();
9562}
9563
9564
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00009565// Change the state of break on exceptions.
9566// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
9567// args[1]: Boolean indicating on/off.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009568static MaybeObject* Runtime_ChangeBreakOnException(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009569 HandleScope scope;
9570 ASSERT(args.length() == 2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00009571 RUNTIME_ASSERT(args[0]->IsNumber());
9572 CONVERT_BOOLEAN_CHECKED(enable, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009573
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00009574 // If the number doesn't match an enum value, the ChangeBreakOnException
9575 // function will default to affecting caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009576 ExceptionBreakType type =
9577 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00009578 // Update break point state.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009579 Debug::ChangeBreakOnException(type, enable);
9580 return Heap::undefined_value();
9581}
9582
9583
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00009584// Returns the state of break on exceptions
9585// args[0]: boolean indicating uncaught exceptions
lrn@chromium.org303ada72010-10-27 09:33:13 +00009586static MaybeObject* Runtime_IsBreakOnException(Arguments args) {
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00009587 HandleScope scope;
9588 ASSERT(args.length() == 1);
9589 RUNTIME_ASSERT(args[0]->IsNumber());
9590
9591 ExceptionBreakType type =
9592 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
9593 bool result = Debug::IsBreakOnException(type);
9594 return Smi::FromInt(result);
9595}
9596
9597
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009598// Prepare for stepping
9599// args[0]: break id for checking execution state
9600// args[1]: step action from the enumeration StepAction
ager@chromium.orga1645e22009-09-09 19:27:10 +00009601// args[2]: number of times to perform the step, for step out it is the number
9602// of frames to step down.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009603static MaybeObject* Runtime_PrepareStep(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009604 HandleScope scope;
9605 ASSERT(args.length() == 3);
9606 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009607 Object* check;
9608 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
9609 if (!maybe_check->ToObject(&check)) return maybe_check;
9610 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009611 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
9612 return Top::Throw(Heap::illegal_argument_symbol());
9613 }
9614
9615 // Get the step action and check validity.
9616 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
9617 if (step_action != StepIn &&
9618 step_action != StepNext &&
9619 step_action != StepOut &&
9620 step_action != StepInMin &&
9621 step_action != StepMin) {
9622 return Top::Throw(Heap::illegal_argument_symbol());
9623 }
9624
9625 // Get the number of steps.
9626 int step_count = NumberToInt32(args[2]);
9627 if (step_count < 1) {
9628 return Top::Throw(Heap::illegal_argument_symbol());
9629 }
9630
ager@chromium.orga1645e22009-09-09 19:27:10 +00009631 // Clear all current stepping setup.
9632 Debug::ClearStepping();
9633
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009634 // Prepare step.
9635 Debug::PrepareStep(static_cast<StepAction>(step_action), step_count);
9636 return Heap::undefined_value();
9637}
9638
9639
9640// Clear all stepping set by PrepareStep.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009641static MaybeObject* Runtime_ClearStepping(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009642 HandleScope scope;
mads.s.ager31e71382008-08-13 09:32:07 +00009643 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009644 Debug::ClearStepping();
9645 return Heap::undefined_value();
9646}
9647
9648
9649// Creates a copy of the with context chain. The copy of the context chain is
9650// is linked to the function context supplied.
9651static Handle<Context> CopyWithContextChain(Handle<Context> context_chain,
9652 Handle<Context> function_context) {
9653 // At the bottom of the chain. Return the function context to link to.
9654 if (context_chain->is_function_context()) {
9655 return function_context;
9656 }
9657
9658 // Recursively copy the with contexts.
9659 Handle<Context> previous(context_chain->previous());
9660 Handle<JSObject> extension(JSObject::cast(context_chain->extension()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00009661 Handle<Context> context = CopyWithContextChain(function_context, previous);
9662 return Factory::NewWithContext(context,
9663 extension,
9664 context_chain->IsCatchContext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009665}
9666
9667
9668// Helper function to find or create the arguments object for
9669// Runtime_DebugEvaluate.
9670static Handle<Object> GetArgumentsObject(JavaScriptFrame* frame,
9671 Handle<JSFunction> function,
ager@chromium.orgb5737492010-07-15 09:29:43 +00009672 Handle<SerializedScopeInfo> scope_info,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009673 const ScopeInfo<>* sinfo,
9674 Handle<Context> function_context) {
9675 // Try to find the value of 'arguments' to pass as parameter. If it is not
9676 // found (that is the debugged function does not reference 'arguments' and
9677 // does not support eval) then create an 'arguments' object.
9678 int index;
9679 if (sinfo->number_of_stack_slots() > 0) {
ager@chromium.orgb5737492010-07-15 09:29:43 +00009680 index = scope_info->StackSlotIndex(Heap::arguments_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009681 if (index != -1) {
9682 return Handle<Object>(frame->GetExpression(index));
9683 }
9684 }
9685
9686 if (sinfo->number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
ager@chromium.orgb5737492010-07-15 09:29:43 +00009687 index = scope_info->ContextSlotIndex(Heap::arguments_symbol(), NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009688 if (index != -1) {
9689 return Handle<Object>(function_context->get(index));
9690 }
9691 }
9692
9693 const int length = frame->GetProvidedParametersCount();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009694 Handle<JSObject> arguments = Factory::NewArgumentsObject(function, length);
9695 Handle<FixedArray> array = Factory::NewFixedArray(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009696
9697 AssertNoAllocation no_gc;
9698 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009699 for (int i = 0; i < length; i++) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009700 array->set(i, frame->GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009701 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009702 arguments->set_elements(*array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009703 return arguments;
9704}
9705
9706
9707// Evaluate a piece of JavaScript in the context of a stack frame for
ager@chromium.org32912102009-01-16 10:38:43 +00009708// debugging. This is accomplished by creating a new context which in its
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009709// extension part has all the parameters and locals of the function on the
9710// stack frame. A function which calls eval with the code to evaluate is then
9711// compiled in this context and called in this context. As this context
9712// replaces the context of the function on the stack frame a new (empty)
9713// function is created as well to be used as the closure for the context.
9714// This function and the context acts as replacements for the function on the
9715// stack frame presenting the same view of the values of parameters and
9716// local variables as if the piece of JavaScript was evaluated at the point
9717// where the function on the stack frame is currently stopped.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009718static MaybeObject* Runtime_DebugEvaluate(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009719 HandleScope scope;
9720
9721 // Check the execution state and decode arguments frame and source to be
9722 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009723 ASSERT(args.length() == 5);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009724 Object* check_result;
9725 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(args);
9726 if (!maybe_check_result->ToObject(&check_result)) {
9727 return maybe_check_result;
9728 }
9729 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009730 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
9731 CONVERT_ARG_CHECKED(String, source, 2);
kasper.lundbd3ec4e2008-07-09 11:06:54 +00009732 CONVERT_BOOLEAN_CHECKED(disable_break, args[3]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009733 Handle<Object> additional_context(args[4]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +00009734
9735 // Handle the processing of break.
9736 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009737
9738 // Get the frame where the debugging is performed.
9739 StackFrame::Id id = UnwrapFrameId(wrapped_id);
9740 JavaScriptFrameIterator it(id);
9741 JavaScriptFrame* frame = it.frame();
9742 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +00009743 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009744 ScopeInfo<> sinfo(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009745
9746 // Traverse the saved contexts chain to find the active context for the
9747 // selected frame.
9748 SaveContext* save = Top::save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009749 while (save != NULL && !save->below(frame)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009750 save = save->prev();
9751 }
9752 ASSERT(save != NULL);
9753 SaveContext savex;
9754 Top::set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009755
9756 // Create the (empty) function replacing the function on the stack frame for
9757 // the purpose of evaluating in the context created below. It is important
9758 // that this function does not describe any parameters and local variables
9759 // in the context. If it does then this will cause problems with the lookup
9760 // in Context::Lookup, where context slots for parameters and local variables
9761 // are looked at before the extension object.
9762 Handle<JSFunction> go_between =
9763 Factory::NewFunction(Factory::empty_string(), Factory::undefined_value());
9764 go_between->set_context(function->context());
9765#ifdef DEBUG
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009766 ScopeInfo<> go_between_sinfo(go_between->shared()->scope_info());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009767 ASSERT(go_between_sinfo.number_of_parameters() == 0);
9768 ASSERT(go_between_sinfo.number_of_context_slots() == 0);
9769#endif
9770
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009771 // Materialize the content of the local scope into a JSObject.
9772 Handle<JSObject> local_scope = MaterializeLocalScope(frame);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009773
9774 // Allocate a new context for the debug evaluation and set the extension
9775 // object build.
9776 Handle<Context> context =
9777 Factory::NewFunctionContext(Context::MIN_CONTEXT_SLOTS, go_between);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009778 context->set_extension(*local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009779 // Copy any with contexts present and chain them in front of this context.
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009780 Handle<Context> frame_context(Context::cast(frame->context()));
9781 Handle<Context> function_context(frame_context->fcontext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009782 context = CopyWithContextChain(frame_context, context);
9783
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009784 if (additional_context->IsJSObject()) {
9785 context = Factory::NewWithContext(context,
9786 Handle<JSObject>::cast(additional_context), false);
9787 }
9788
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009789 // Wrap the evaluation statement in a new function compiled in the newly
9790 // created context. The function has one parameter which has to be called
9791 // 'arguments'. This it to have access to what would have been 'arguments' in
ager@chromium.org32912102009-01-16 10:38:43 +00009792 // the function being debugged.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009793 // function(arguments,__source__) {return eval(__source__);}
9794 static const char* source_str =
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00009795 "(function(arguments,__source__){return eval(__source__);})";
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009796 static const int source_str_length = StrLength(source_str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009797 Handle<String> function_source =
9798 Factory::NewStringFromAscii(Vector<const char>(source_str,
9799 source_str_length));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009800 Handle<SharedFunctionInfo> shared =
ager@chromium.org381abbb2009-02-25 13:23:22 +00009801 Compiler::CompileEval(function_source,
9802 context,
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009803 context->IsGlobalContext());
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009804 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009805 Handle<JSFunction> compiled_function =
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009806 Factory::NewFunctionFromSharedFunctionInfo(shared, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009807
9808 // Invoke the result of the compilation to get the evaluation function.
9809 bool has_pending_exception;
9810 Handle<Object> receiver(frame->receiver());
9811 Handle<Object> evaluation_function =
9812 Execution::Call(compiled_function, receiver, 0, NULL,
9813 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00009814 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009815
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009816 Handle<Object> arguments = GetArgumentsObject(frame, function, scope_info,
9817 &sinfo, function_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009818
9819 // Invoke the evaluation function and return the result.
9820 const int argc = 2;
9821 Object** argv[argc] = { arguments.location(),
9822 Handle<Object>::cast(source).location() };
9823 Handle<Object> result =
9824 Execution::Call(Handle<JSFunction>::cast(evaluation_function), receiver,
9825 argc, argv, &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00009826 if (has_pending_exception) return Failure::Exception();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009827
9828 // Skip the global proxy as it has no properties and always delegates to the
9829 // real global object.
9830 if (result->IsJSGlobalProxy()) {
9831 result = Handle<JSObject>(JSObject::cast(result->GetPrototype()));
9832 }
9833
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009834 return *result;
9835}
9836
9837
lrn@chromium.org303ada72010-10-27 09:33:13 +00009838static MaybeObject* Runtime_DebugEvaluateGlobal(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009839 HandleScope scope;
9840
9841 // Check the execution state and decode arguments frame and source to be
9842 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009843 ASSERT(args.length() == 4);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009844 Object* check_result;
9845 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(args);
9846 if (!maybe_check_result->ToObject(&check_result)) {
9847 return maybe_check_result;
9848 }
9849 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009850 CONVERT_ARG_CHECKED(String, source, 1);
kasper.lundbd3ec4e2008-07-09 11:06:54 +00009851 CONVERT_BOOLEAN_CHECKED(disable_break, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009852 Handle<Object> additional_context(args[3]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +00009853
9854 // Handle the processing of break.
9855 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009856
9857 // Enter the top context from before the debugger was invoked.
9858 SaveContext save;
9859 SaveContext* top = &save;
9860 while (top != NULL && *top->context() == *Debug::debug_context()) {
9861 top = top->prev();
9862 }
9863 if (top != NULL) {
9864 Top::set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009865 }
9866
9867 // Get the global context now set to the top context from before the
9868 // debugger was invoked.
9869 Handle<Context> context = Top::global_context();
9870
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009871 bool is_global = true;
9872
9873 if (additional_context->IsJSObject()) {
9874 // Create a function context first, than put 'with' context on top of it.
9875 Handle<JSFunction> go_between = Factory::NewFunction(
9876 Factory::empty_string(), Factory::undefined_value());
9877 go_between->set_context(*context);
9878 context =
9879 Factory::NewFunctionContext(Context::MIN_CONTEXT_SLOTS, go_between);
9880 context->set_extension(JSObject::cast(*additional_context));
9881 is_global = false;
9882 }
9883
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009884 // Compile the source to be evaluated.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009885 Handle<SharedFunctionInfo> shared =
9886 Compiler::CompileEval(source,
9887 context,
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009888 is_global);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009889 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009890 Handle<JSFunction> compiled_function =
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009891 Handle<JSFunction>(Factory::NewFunctionFromSharedFunctionInfo(shared,
9892 context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009893
9894 // Invoke the result of the compilation to get the evaluation function.
9895 bool has_pending_exception;
9896 Handle<Object> receiver = Top::global();
9897 Handle<Object> result =
9898 Execution::Call(compiled_function, receiver, 0, NULL,
9899 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00009900 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009901 return *result;
9902}
9903
9904
lrn@chromium.org303ada72010-10-27 09:33:13 +00009905static MaybeObject* Runtime_DebugGetLoadedScripts(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009906 HandleScope scope;
mads.s.ager31e71382008-08-13 09:32:07 +00009907 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009908
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009909 // Fill the script objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +00009910 Handle<FixedArray> instances = Debug::GetLoadedScripts();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009911
9912 // Convert the script objects to proper JS objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +00009913 for (int i = 0; i < instances->length(); i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00009914 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
9915 // Get the script wrapper in a local handle before calling GetScriptWrapper,
9916 // because using
9917 // instances->set(i, *GetScriptWrapper(script))
9918 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
9919 // already have deferenced the instances handle.
9920 Handle<JSValue> wrapper = GetScriptWrapper(script);
9921 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009922 }
9923
9924 // Return result as a JS array.
9925 Handle<JSObject> result = Factory::NewJSObject(Top::array_function());
9926 Handle<JSArray>::cast(result)->SetContent(*instances);
9927 return *result;
9928}
9929
9930
9931// Helper function used by Runtime_DebugReferencedBy below.
9932static int DebugReferencedBy(JSObject* target,
9933 Object* instance_filter, int max_references,
9934 FixedArray* instances, int instances_size,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009935 JSFunction* arguments_function) {
9936 NoHandleAllocation ha;
9937 AssertNoAllocation no_alloc;
9938
9939 // Iterate the heap.
9940 int count = 0;
9941 JSObject* last = NULL;
9942 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009943 HeapObject* heap_obj = NULL;
9944 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009945 (max_references == 0 || count < max_references)) {
9946 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009947 if (heap_obj->IsJSObject()) {
9948 // Skip context extension objects and argument arrays as these are
9949 // checked in the context of functions using them.
9950 JSObject* obj = JSObject::cast(heap_obj);
iposva@chromium.org245aa852009-02-10 00:49:54 +00009951 if (obj->IsJSContextExtensionObject() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009952 obj->map()->constructor() == arguments_function) {
9953 continue;
9954 }
9955
9956 // Check if the JS object has a reference to the object looked for.
9957 if (obj->ReferencesObject(target)) {
9958 // Check instance filter if supplied. This is normally used to avoid
9959 // references from mirror objects (see Runtime_IsInPrototypeChain).
9960 if (!instance_filter->IsUndefined()) {
9961 Object* V = obj;
9962 while (true) {
9963 Object* prototype = V->GetPrototype();
9964 if (prototype->IsNull()) {
9965 break;
9966 }
9967 if (instance_filter == prototype) {
9968 obj = NULL; // Don't add this object.
9969 break;
9970 }
9971 V = prototype;
9972 }
9973 }
9974
9975 if (obj != NULL) {
9976 // Valid reference found add to instance array if supplied an update
9977 // count.
9978 if (instances != NULL && count < instances_size) {
9979 instances->set(count, obj);
9980 }
9981 last = obj;
9982 count++;
9983 }
9984 }
9985 }
9986 }
9987
9988 // Check for circular reference only. This can happen when the object is only
9989 // referenced from mirrors and has a circular reference in which case the
9990 // object is not really alive and would have been garbage collected if not
9991 // referenced from the mirror.
9992 if (count == 1 && last == target) {
9993 count = 0;
9994 }
9995
9996 // Return the number of referencing objects found.
9997 return count;
9998}
9999
10000
10001// Scan the heap for objects with direct references to an object
10002// args[0]: the object to find references to
10003// args[1]: constructor function for instances to exclude (Mirror)
10004// args[2]: the the maximum number of objects to return
lrn@chromium.org303ada72010-10-27 09:33:13 +000010005static MaybeObject* Runtime_DebugReferencedBy(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010006 ASSERT(args.length() == 3);
10007
10008 // First perform a full GC in order to avoid references from dead objects.
ager@chromium.orgab99eea2009-08-25 07:05:41 +000010009 Heap::CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010010
10011 // Check parameters.
10012 CONVERT_CHECKED(JSObject, target, args[0]);
10013 Object* instance_filter = args[1];
10014 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
10015 instance_filter->IsJSObject());
10016 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
10017 RUNTIME_ASSERT(max_references >= 0);
10018
10019 // Get the constructor function for context extension and arguments array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010020 JSObject* arguments_boilerplate =
10021 Top::context()->global_context()->arguments_boilerplate();
10022 JSFunction* arguments_function =
10023 JSFunction::cast(arguments_boilerplate->map()->constructor());
10024
10025 // Get the number of referencing objects.
10026 int count;
10027 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000010028 NULL, 0, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010029
10030 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010031 Object* object;
10032 { MaybeObject* maybe_object = Heap::AllocateFixedArray(count);
10033 if (!maybe_object->ToObject(&object)) return maybe_object;
10034 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010035 FixedArray* instances = FixedArray::cast(object);
10036
10037 // Fill the referencing objects.
10038 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000010039 instances, count, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010040
10041 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010042 Object* result;
10043 { MaybeObject* maybe_result = Heap::AllocateJSObject(
10044 Top::context()->global_context()->array_function());
10045 if (!maybe_result->ToObject(&result)) return maybe_result;
10046 }
10047 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010048 return result;
10049}
10050
10051
10052// Helper function used by Runtime_DebugConstructedBy below.
10053static int DebugConstructedBy(JSFunction* constructor, int max_references,
10054 FixedArray* instances, int instances_size) {
10055 AssertNoAllocation no_alloc;
10056
10057 // Iterate the heap.
10058 int count = 0;
10059 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010060 HeapObject* heap_obj = NULL;
10061 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010062 (max_references == 0 || count < max_references)) {
10063 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010064 if (heap_obj->IsJSObject()) {
10065 JSObject* obj = JSObject::cast(heap_obj);
10066 if (obj->map()->constructor() == constructor) {
10067 // Valid reference found add to instance array if supplied an update
10068 // count.
10069 if (instances != NULL && count < instances_size) {
10070 instances->set(count, obj);
10071 }
10072 count++;
10073 }
10074 }
10075 }
10076
10077 // Return the number of referencing objects found.
10078 return count;
10079}
10080
10081
10082// Scan the heap for objects constructed by a specific function.
10083// args[0]: the constructor to find instances of
10084// args[1]: the the maximum number of objects to return
lrn@chromium.org303ada72010-10-27 09:33:13 +000010085static MaybeObject* Runtime_DebugConstructedBy(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010086 ASSERT(args.length() == 2);
10087
10088 // First perform a full GC in order to avoid dead objects.
ager@chromium.orgab99eea2009-08-25 07:05:41 +000010089 Heap::CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010090
10091 // Check parameters.
10092 CONVERT_CHECKED(JSFunction, constructor, args[0]);
10093 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
10094 RUNTIME_ASSERT(max_references >= 0);
10095
10096 // Get the number of referencing objects.
10097 int count;
10098 count = DebugConstructedBy(constructor, max_references, NULL, 0);
10099
10100 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010101 Object* object;
10102 { MaybeObject* maybe_object = Heap::AllocateFixedArray(count);
10103 if (!maybe_object->ToObject(&object)) return maybe_object;
10104 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010105 FixedArray* instances = FixedArray::cast(object);
10106
10107 // Fill the referencing objects.
10108 count = DebugConstructedBy(constructor, max_references, instances, count);
10109
10110 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010111 Object* result;
10112 { MaybeObject* maybe_result = Heap::AllocateJSObject(
10113 Top::context()->global_context()->array_function());
10114 if (!maybe_result->ToObject(&result)) return maybe_result;
10115 }
10116 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010117 return result;
10118}
10119
10120
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010121// Find the effective prototype object as returned by __proto__.
10122// args[0]: the object to find the prototype for.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010123static MaybeObject* Runtime_DebugGetPrototype(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010124 ASSERT(args.length() == 1);
10125
10126 CONVERT_CHECKED(JSObject, obj, args[0]);
10127
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010128 // Use the __proto__ accessor.
10129 return Accessors::ObjectPrototype.getter(obj, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010130}
10131
10132
lrn@chromium.org303ada72010-10-27 09:33:13 +000010133static MaybeObject* Runtime_SystemBreak(Arguments args) {
mads.s.ager31e71382008-08-13 09:32:07 +000010134 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010135 CPU::DebugBreak();
10136 return Heap::undefined_value();
10137}
10138
10139
lrn@chromium.org303ada72010-10-27 09:33:13 +000010140static MaybeObject* Runtime_DebugDisassembleFunction(Arguments args) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010141#ifdef DEBUG
10142 HandleScope scope;
10143 ASSERT(args.length() == 1);
10144 // Get the function and make sure it is compiled.
10145 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010146 Handle<SharedFunctionInfo> shared(func->shared());
10147 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010148 return Failure::Exception();
10149 }
10150 func->code()->PrintLn();
10151#endif // DEBUG
10152 return Heap::undefined_value();
10153}
ager@chromium.org9085a012009-05-11 19:22:57 +000010154
10155
lrn@chromium.org303ada72010-10-27 09:33:13 +000010156static MaybeObject* Runtime_DebugDisassembleConstructor(Arguments args) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000010157#ifdef DEBUG
10158 HandleScope scope;
10159 ASSERT(args.length() == 1);
10160 // Get the function and make sure it is compiled.
10161 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010162 Handle<SharedFunctionInfo> shared(func->shared());
10163 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000010164 return Failure::Exception();
10165 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010166 shared->construct_stub()->PrintLn();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000010167#endif // DEBUG
10168 return Heap::undefined_value();
10169}
10170
10171
lrn@chromium.org303ada72010-10-27 09:33:13 +000010172static MaybeObject* Runtime_FunctionGetInferredName(Arguments args) {
ager@chromium.org9085a012009-05-11 19:22:57 +000010173 NoHandleAllocation ha;
10174 ASSERT(args.length() == 1);
10175
10176 CONVERT_CHECKED(JSFunction, f, args[0]);
10177 return f->shared()->inferred_name();
10178}
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010179
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010180
10181static int FindSharedFunctionInfosForScript(Script* script,
10182 FixedArray* buffer) {
10183 AssertNoAllocation no_allocations;
10184
10185 int counter = 0;
10186 int buffer_size = buffer->length();
10187 HeapIterator iterator;
10188 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
10189 ASSERT(obj != NULL);
10190 if (!obj->IsSharedFunctionInfo()) {
10191 continue;
10192 }
10193 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
10194 if (shared->script() != script) {
10195 continue;
10196 }
10197 if (counter < buffer_size) {
10198 buffer->set(counter, shared);
10199 }
10200 counter++;
10201 }
10202 return counter;
10203}
10204
10205// For a script finds all SharedFunctionInfo's in the heap that points
10206// to this script. Returns JSArray of SharedFunctionInfo wrapped
10207// in OpaqueReferences.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010208static MaybeObject* Runtime_LiveEditFindSharedFunctionInfosForScript(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010209 Arguments args) {
10210 ASSERT(args.length() == 1);
10211 HandleScope scope;
10212 CONVERT_CHECKED(JSValue, script_value, args[0]);
10213
10214 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
10215
10216 const int kBufferSize = 32;
10217
10218 Handle<FixedArray> array;
10219 array = Factory::NewFixedArray(kBufferSize);
10220 int number = FindSharedFunctionInfosForScript(*script, *array);
10221 if (number > kBufferSize) {
10222 array = Factory::NewFixedArray(number);
10223 FindSharedFunctionInfosForScript(*script, *array);
10224 }
10225
10226 Handle<JSArray> result = Factory::NewJSArrayWithElements(array);
10227 result->set_length(Smi::FromInt(number));
10228
10229 LiveEdit::WrapSharedFunctionInfos(result);
10230
10231 return *result;
10232}
10233
10234// For a script calculates compilation information about all its functions.
10235// The script source is explicitly specified by the second argument.
10236// The source of the actual script is not used, however it is important that
10237// all generated code keeps references to this particular instance of script.
10238// Returns a JSArray of compilation infos. The array is ordered so that
10239// each function with all its descendant is always stored in a continues range
10240// with the function itself going first. The root function is a script function.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010241static MaybeObject* Runtime_LiveEditGatherCompileInfo(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010242 ASSERT(args.length() == 2);
10243 HandleScope scope;
10244 CONVERT_CHECKED(JSValue, script, args[0]);
10245 CONVERT_ARG_CHECKED(String, source, 1);
10246 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
10247
10248 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
10249
10250 if (Top::has_pending_exception()) {
10251 return Failure::Exception();
10252 }
10253
10254 return result;
10255}
10256
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010257// Changes the source of the script to a new_source.
10258// If old_script_name is provided (i.e. is a String), also creates a copy of
10259// the script with its original source and sends notification to debugger.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010260static MaybeObject* Runtime_LiveEditReplaceScript(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010261 ASSERT(args.length() == 3);
10262 HandleScope scope;
10263 CONVERT_CHECKED(JSValue, original_script_value, args[0]);
10264 CONVERT_ARG_CHECKED(String, new_source, 1);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010265 Handle<Object> old_script_name(args[2]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010266
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010267 CONVERT_CHECKED(Script, original_script_pointer,
10268 original_script_value->value());
10269 Handle<Script> original_script(original_script_pointer);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010270
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010271 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
10272 new_source,
10273 old_script_name);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010274
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010275 if (old_script->IsScript()) {
10276 Handle<Script> script_handle(Script::cast(old_script));
10277 return *(GetScriptWrapper(script_handle));
10278 } else {
10279 return Heap::null_value();
10280 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010281}
10282
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010283
10284static MaybeObject* Runtime_LiveEditFunctionSourceUpdated(Arguments args) {
10285 ASSERT(args.length() == 1);
10286 HandleScope scope;
10287 CONVERT_ARG_CHECKED(JSArray, shared_info, 0);
10288 return LiveEdit::FunctionSourceUpdated(shared_info);
10289}
10290
10291
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010292// Replaces code of SharedFunctionInfo with a new one.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010293static MaybeObject* Runtime_LiveEditReplaceFunctionCode(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010294 ASSERT(args.length() == 2);
10295 HandleScope scope;
10296 CONVERT_ARG_CHECKED(JSArray, new_compile_info, 0);
10297 CONVERT_ARG_CHECKED(JSArray, shared_info, 1);
10298
ager@chromium.orgac091b72010-05-05 07:34:42 +000010299 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010300}
10301
10302// Connects SharedFunctionInfo to another script.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010303static MaybeObject* Runtime_LiveEditFunctionSetScript(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010304 ASSERT(args.length() == 2);
10305 HandleScope scope;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010306 Handle<Object> function_object(args[0]);
10307 Handle<Object> script_object(args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010308
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010309 if (function_object->IsJSValue()) {
10310 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
10311 if (script_object->IsJSValue()) {
10312 CONVERT_CHECKED(Script, script, JSValue::cast(*script_object)->value());
10313 script_object = Handle<Object>(script);
10314 }
10315
10316 LiveEdit::SetFunctionScript(function_wrapper, script_object);
10317 } else {
10318 // Just ignore this. We may not have a SharedFunctionInfo for some functions
10319 // and we check it in this function.
10320 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010321
10322 return Heap::undefined_value();
10323}
10324
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010325
10326// In a code of a parent function replaces original function as embedded object
10327// with a substitution one.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010328static MaybeObject* Runtime_LiveEditReplaceRefToNestedFunction(Arguments args) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010329 ASSERT(args.length() == 3);
10330 HandleScope scope;
10331
10332 CONVERT_ARG_CHECKED(JSValue, parent_wrapper, 0);
10333 CONVERT_ARG_CHECKED(JSValue, orig_wrapper, 1);
10334 CONVERT_ARG_CHECKED(JSValue, subst_wrapper, 2);
10335
10336 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
10337 subst_wrapper);
10338
10339 return Heap::undefined_value();
10340}
10341
10342
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010343// Updates positions of a shared function info (first parameter) according
10344// to script source change. Text change is described in second parameter as
10345// array of groups of 3 numbers:
10346// (change_begin, change_end, change_end_new_position).
10347// Each group describes a change in text; groups are sorted by change_begin.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010348static MaybeObject* Runtime_LiveEditPatchFunctionPositions(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010349 ASSERT(args.length() == 2);
10350 HandleScope scope;
10351 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
10352 CONVERT_ARG_CHECKED(JSArray, position_change_array, 1);
10353
ager@chromium.orgac091b72010-05-05 07:34:42 +000010354 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010355}
10356
10357
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010358// For array of SharedFunctionInfo's (each wrapped in JSValue)
10359// checks that none of them have activations on stacks (of any thread).
10360// Returns array of the same length with corresponding results of
10361// LiveEdit::FunctionPatchabilityStatus type.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010362static MaybeObject* Runtime_LiveEditCheckAndDropActivations(Arguments args) {
ager@chromium.org357bf652010-04-12 11:30:10 +000010363 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010364 HandleScope scope;
10365 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
ager@chromium.org357bf652010-04-12 11:30:10 +000010366 CONVERT_BOOLEAN_CHECKED(do_drop, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010367
ager@chromium.org357bf652010-04-12 11:30:10 +000010368 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010369}
10370
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000010371// Compares 2 strings line-by-line, then token-wise and returns diff in form
10372// of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
10373// of diff chunks.
10374static MaybeObject* Runtime_LiveEditCompareStrings(Arguments args) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010375 ASSERT(args.length() == 2);
10376 HandleScope scope;
10377 CONVERT_ARG_CHECKED(String, s1, 0);
10378 CONVERT_ARG_CHECKED(String, s2, 1);
10379
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000010380 return *LiveEdit::CompareStrings(s1, s2);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010381}
10382
10383
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010384
fschneider@chromium.org086aac62010-03-17 13:18:24 +000010385// A testing entry. Returns statement position which is the closest to
10386// source_position.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010387static MaybeObject* Runtime_GetFunctionCodePositionFromSource(Arguments args) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +000010388 ASSERT(args.length() == 2);
10389 HandleScope scope;
10390 CONVERT_ARG_CHECKED(JSFunction, function, 0);
10391 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
10392
10393 Handle<Code> code(function->code());
10394
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010395 if (code->kind() != Code::FUNCTION &&
10396 code->kind() != Code::OPTIMIZED_FUNCTION) {
10397 return Heap::undefined_value();
10398 }
10399
10400 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
fschneider@chromium.org086aac62010-03-17 13:18:24 +000010401 int closest_pc = 0;
10402 int distance = kMaxInt;
10403 while (!it.done()) {
10404 int statement_position = static_cast<int>(it.rinfo()->data());
10405 // Check if this break point is closer that what was previously found.
10406 if (source_position <= statement_position &&
10407 statement_position - source_position < distance) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +000010408 closest_pc =
10409 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
fschneider@chromium.org086aac62010-03-17 13:18:24 +000010410 distance = statement_position - source_position;
10411 // Check whether we can't get any closer.
10412 if (distance == 0) break;
10413 }
10414 it.next();
10415 }
10416
10417 return Smi::FromInt(closest_pc);
10418}
10419
10420
ager@chromium.org357bf652010-04-12 11:30:10 +000010421// Calls specified function with or without entering the debugger.
10422// This is used in unit tests to run code as if debugger is entered or simply
10423// to have a stack with C++ frame in the middle.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010424static MaybeObject* Runtime_ExecuteInDebugContext(Arguments args) {
ager@chromium.org357bf652010-04-12 11:30:10 +000010425 ASSERT(args.length() == 2);
10426 HandleScope scope;
10427 CONVERT_ARG_CHECKED(JSFunction, function, 0);
10428 CONVERT_BOOLEAN_CHECKED(without_debugger, args[1]);
10429
10430 Handle<Object> result;
10431 bool pending_exception;
10432 {
10433 if (without_debugger) {
10434 result = Execution::Call(function, Top::global(), 0, NULL,
10435 &pending_exception);
10436 } else {
10437 EnterDebugger enter_debugger;
10438 result = Execution::Call(function, Top::global(), 0, NULL,
10439 &pending_exception);
10440 }
10441 }
10442 if (!pending_exception) {
10443 return *result;
10444 } else {
10445 return Failure::Exception();
10446 }
10447}
10448
10449
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000010450// Sets a v8 flag.
10451static MaybeObject* Runtime_SetFlags(Arguments args) {
10452 CONVERT_CHECKED(String, arg, args[0]);
10453 SmartPointer<char> flags =
10454 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
10455 FlagList::SetFlagsFromString(*flags, StrLength(*flags));
10456 return Heap::undefined_value();
10457}
10458
10459
10460// Performs a GC.
10461// Presently, it only does a full GC.
10462static MaybeObject* Runtime_CollectGarbage(Arguments args) {
10463 Heap::CollectAllGarbage(true);
10464 return Heap::undefined_value();
10465}
10466
10467
10468// Gets the current heap usage.
10469static MaybeObject* Runtime_GetHeapUsage(Arguments args) {
10470 int usage = static_cast<int>(Heap::SizeOfObjects());
10471 if (!Smi::IsValid(usage)) {
10472 return *Factory::NewNumberFromInt(usage);
10473 }
10474 return Smi::FromInt(usage);
10475}
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010476#endif // ENABLE_DEBUGGER_SUPPORT
10477
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010478
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000010479#ifdef ENABLE_LOGGING_AND_PROFILING
lrn@chromium.org303ada72010-10-27 09:33:13 +000010480static MaybeObject* Runtime_ProfilerResume(Arguments args) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010481 NoHandleAllocation ha;
ager@chromium.org5c838252010-02-19 08:53:10 +000010482 ASSERT(args.length() == 2);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010483
10484 CONVERT_CHECKED(Smi, smi_modules, args[0]);
ager@chromium.org5c838252010-02-19 08:53:10 +000010485 CONVERT_CHECKED(Smi, smi_tag, args[1]);
10486 v8::V8::ResumeProfilerEx(smi_modules->value(), smi_tag->value());
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010487 return Heap::undefined_value();
10488}
10489
10490
lrn@chromium.org303ada72010-10-27 09:33:13 +000010491static MaybeObject* Runtime_ProfilerPause(Arguments args) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010492 NoHandleAllocation ha;
ager@chromium.org5c838252010-02-19 08:53:10 +000010493 ASSERT(args.length() == 2);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010494
10495 CONVERT_CHECKED(Smi, smi_modules, args[0]);
ager@chromium.org5c838252010-02-19 08:53:10 +000010496 CONVERT_CHECKED(Smi, smi_tag, args[1]);
10497 v8::V8::PauseProfilerEx(smi_modules->value(), smi_tag->value());
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010498 return Heap::undefined_value();
10499}
10500
10501#endif // ENABLE_LOGGING_AND_PROFILING
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010502
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010503// Finds the script object from the script data. NOTE: This operation uses
10504// heap traversal to find the function generated for the source position
10505// for the requested break point. For lazily compiled functions several heap
10506// traversals might be required rendering this operation as a rather slow
10507// operation. However for setting break points which is normally done through
10508// some kind of user interaction the performance is not crucial.
10509static Handle<Object> Runtime_GetScriptFromScriptName(
10510 Handle<String> script_name) {
10511 // Scan the heap for Script objects to find the script with the requested
10512 // script data.
10513 Handle<Script> script;
10514 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010515 HeapObject* obj = NULL;
10516 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010517 // If a script is found check if it has the script data requested.
10518 if (obj->IsScript()) {
10519 if (Script::cast(obj)->name()->IsString()) {
10520 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
10521 script = Handle<Script>(Script::cast(obj));
10522 }
10523 }
10524 }
10525 }
10526
10527 // If no script with the requested script data is found return undefined.
10528 if (script.is_null()) return Factory::undefined_value();
10529
10530 // Return the script found.
10531 return GetScriptWrapper(script);
10532}
10533
10534
10535// Get the script object from script data. NOTE: Regarding performance
10536// see the NOTE for GetScriptFromScriptData.
10537// args[0]: script data for the script to find the source for
lrn@chromium.org303ada72010-10-27 09:33:13 +000010538static MaybeObject* Runtime_GetScript(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010539 HandleScope scope;
10540
10541 ASSERT(args.length() == 1);
10542
10543 CONVERT_CHECKED(String, script_name, args[0]);
10544
10545 // Find the requested script.
10546 Handle<Object> result =
10547 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
10548 return *result;
10549}
10550
10551
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010552// Determines whether the given stack frame should be displayed in
10553// a stack trace. The caller is the error constructor that asked
10554// for the stack trace to be collected. The first time a construct
10555// call to this function is encountered it is skipped. The seen_caller
10556// in/out parameter is used to remember if the caller has been seen
10557// yet.
10558static bool ShowFrameInStackTrace(StackFrame* raw_frame, Object* caller,
10559 bool* seen_caller) {
10560 // Only display JS frames.
10561 if (!raw_frame->is_java_script())
10562 return false;
10563 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
10564 Object* raw_fun = frame->function();
10565 // Not sure when this can happen but skip it just in case.
10566 if (!raw_fun->IsJSFunction())
10567 return false;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010568 if ((raw_fun == caller) && !(*seen_caller)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010569 *seen_caller = true;
10570 return false;
10571 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010572 // Skip all frames until we've seen the caller. Also, skip the most
10573 // obvious builtin calls. Some builtin calls (such as Number.ADD
10574 // which is invoked using 'call') are very difficult to recognize
10575 // so we're leaving them in for now.
10576 return *seen_caller && !frame->receiver()->IsJSBuiltinsObject();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010577}
10578
10579
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010580// Collect the raw data for a stack trace. Returns an array of 4
10581// element segments each containing a receiver, function, code and
10582// native code offset.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010583static MaybeObject* Runtime_CollectStackTrace(Arguments args) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010584 ASSERT_EQ(args.length(), 2);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010585 Handle<Object> caller = args.at<Object>(0);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010586 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[1]);
10587
10588 HandleScope scope;
10589
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000010590 limit = Max(limit, 0); // Ensure that limit is not negative.
10591 int initial_size = Min(limit, 10);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010592 Handle<JSArray> result = Factory::NewJSArray(initial_size * 4);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010593
10594 StackFrameIterator iter;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010595 // If the caller parameter is a function we skip frames until we're
10596 // under it before starting to collect.
10597 bool seen_caller = !caller->IsJSFunction();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010598 int cursor = 0;
10599 int frames_seen = 0;
10600 while (!iter.done() && frames_seen < limit) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010601 StackFrame* raw_frame = iter.frame();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010602 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010603 frames_seen++;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010604 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010605 List<FrameSummary> frames(3); // Max 2 levels of inlining.
10606 frame->Summarize(&frames);
10607 for (int i = frames.length() - 1; i >= 0; i--) {
10608 Handle<Object> recv = frames[i].receiver();
10609 Handle<JSFunction> fun = frames[i].function();
10610 Handle<Code> code = frames[i].code();
10611 Handle<Smi> offset(Smi::FromInt(frames[i].offset()));
10612 FixedArray* elements = FixedArray::cast(result->elements());
10613 if (cursor + 3 < elements->length()) {
10614 elements->set(cursor++, *recv);
10615 elements->set(cursor++, *fun);
10616 elements->set(cursor++, *code);
10617 elements->set(cursor++, *offset);
10618 } else {
10619 SetElement(result, cursor++, recv);
10620 SetElement(result, cursor++, fun);
10621 SetElement(result, cursor++, code);
10622 SetElement(result, cursor++, offset);
10623 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010624 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010625 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010626 iter.Advance();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010627 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010628
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010629 result->set_length(Smi::FromInt(cursor));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010630 return *result;
10631}
10632
10633
ager@chromium.org3811b432009-10-28 14:53:37 +000010634// Returns V8 version as a string.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010635static MaybeObject* Runtime_GetV8Version(Arguments args) {
ager@chromium.org3811b432009-10-28 14:53:37 +000010636 ASSERT_EQ(args.length(), 0);
10637
10638 NoHandleAllocation ha;
10639
10640 const char* version_string = v8::V8::GetVersion();
10641
10642 return Heap::AllocateStringFromAscii(CStrVector(version_string), NOT_TENURED);
10643}
10644
10645
lrn@chromium.org303ada72010-10-27 09:33:13 +000010646static MaybeObject* Runtime_Abort(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010647 ASSERT(args.length() == 2);
10648 OS::PrintError("abort: %s\n", reinterpret_cast<char*>(args[0]) +
10649 Smi::cast(args[1])->value());
10650 Top::PrintStack();
10651 OS::Abort();
10652 UNREACHABLE();
10653 return NULL;
10654}
10655
10656
lrn@chromium.org303ada72010-10-27 09:33:13 +000010657static MaybeObject* Runtime_GetFromCache(Arguments args) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010658 // This is only called from codegen, so checks might be more lax.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000010659 CONVERT_CHECKED(JSFunctionResultCache, cache, args[0]);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010660 Object* key = args[1];
10661
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000010662 int finger_index = cache->finger_index();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010663 Object* o = cache->get(finger_index);
10664 if (o == key) {
10665 // The fastest case: hit the same place again.
10666 return cache->get(finger_index + 1);
10667 }
10668
10669 for (int i = finger_index - 2;
10670 i >= JSFunctionResultCache::kEntriesIndex;
10671 i -= 2) {
10672 o = cache->get(i);
10673 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000010674 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010675 return cache->get(i + 1);
10676 }
10677 }
10678
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000010679 int size = cache->size();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010680 ASSERT(size <= cache->length());
10681
10682 for (int i = size - 2; i > finger_index; i -= 2) {
10683 o = cache->get(i);
10684 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000010685 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010686 return cache->get(i + 1);
10687 }
10688 }
10689
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000010690 // There is no value in the cache. Invoke the function and cache result.
10691 HandleScope scope;
10692
10693 Handle<JSFunctionResultCache> cache_handle(cache);
10694 Handle<Object> key_handle(key);
10695 Handle<Object> value;
10696 {
10697 Handle<JSFunction> factory(JSFunction::cast(
10698 cache_handle->get(JSFunctionResultCache::kFactoryIndex)));
10699 // TODO(antonm): consider passing a receiver when constructing a cache.
10700 Handle<Object> receiver(Top::global_context()->global());
10701 // This handle is nor shared, nor used later, so it's safe.
10702 Object** argv[] = { key_handle.location() };
10703 bool pending_exception = false;
10704 value = Execution::Call(factory,
10705 receiver,
10706 1,
10707 argv,
10708 &pending_exception);
10709 if (pending_exception) return Failure::Exception();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010710 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000010711
10712#ifdef DEBUG
10713 cache_handle->JSFunctionResultCacheVerify();
10714#endif
10715
10716 // Function invocation may have cleared the cache. Reread all the data.
10717 finger_index = cache_handle->finger_index();
10718 size = cache_handle->size();
10719
10720 // If we have spare room, put new data into it, otherwise evict post finger
10721 // entry which is likely to be the least recently used.
10722 int index = -1;
10723 if (size < cache_handle->length()) {
10724 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize);
10725 index = size;
10726 } else {
10727 index = finger_index + JSFunctionResultCache::kEntrySize;
10728 if (index == cache_handle->length()) {
10729 index = JSFunctionResultCache::kEntriesIndex;
10730 }
10731 }
10732
10733 ASSERT(index % 2 == 0);
10734 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
10735 ASSERT(index < cache_handle->length());
10736
10737 cache_handle->set(index, *key_handle);
10738 cache_handle->set(index + 1, *value);
10739 cache_handle->set_finger_index(index);
10740
10741#ifdef DEBUG
10742 cache_handle->JSFunctionResultCacheVerify();
10743#endif
10744
10745 return *value;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010746}
10747
kasper.lund44510672008-07-25 07:37:58 +000010748#ifdef DEBUG
10749// ListNatives is ONLY used by the fuzz-natives.js in debug mode
10750// Exclude the code in release mode.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010751static MaybeObject* Runtime_ListNatives(Arguments args) {
mads.s.ager31e71382008-08-13 09:32:07 +000010752 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010753 HandleScope scope;
10754 Handle<JSArray> result = Factory::NewJSArray(0);
10755 int index = 0;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000010756 bool inline_runtime_functions = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +000010757#define ADD_ENTRY(Name, argc, ressize) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010758 { \
10759 HandleScope inner; \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000010760 Handle<String> name; \
10761 /* Inline runtime functions have an underscore in front of the name. */ \
10762 if (inline_runtime_functions) { \
10763 name = Factory::NewStringFromAscii( \
10764 Vector<const char>("_" #Name, StrLength("_" #Name))); \
10765 } else { \
10766 name = Factory::NewStringFromAscii( \
10767 Vector<const char>(#Name, StrLength(#Name))); \
10768 } \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010769 Handle<JSArray> pair = Factory::NewJSArray(0); \
10770 SetElement(pair, 0, name); \
10771 SetElement(pair, 1, Handle<Smi>(Smi::FromInt(argc))); \
10772 SetElement(result, index++, pair); \
10773 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000010774 inline_runtime_functions = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010775 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000010776 inline_runtime_functions = true;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010777 INLINE_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000010778 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010779#undef ADD_ENTRY
10780 return *result;
10781}
kasper.lund44510672008-07-25 07:37:58 +000010782#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010783
10784
lrn@chromium.org303ada72010-10-27 09:33:13 +000010785static MaybeObject* Runtime_Log(Arguments args) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000010786 ASSERT(args.length() == 2);
ager@chromium.org381abbb2009-02-25 13:23:22 +000010787 CONVERT_CHECKED(String, format, args[0]);
10788 CONVERT_CHECKED(JSArray, elms, args[1]);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000010789 Vector<const char> chars = format->ToAsciiVector();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000010790 Logger::LogRuntime(chars, elms);
10791 return Heap::undefined_value();
10792}
10793
10794
lrn@chromium.org303ada72010-10-27 09:33:13 +000010795static MaybeObject* Runtime_IS_VAR(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010796 UNREACHABLE(); // implemented as macro in the parser
10797 return NULL;
10798}
10799
10800
10801// ----------------------------------------------------------------------------
10802// Implementation of Runtime
10803
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010804#define F(name, number_of_args, result_size) \
10805 { Runtime::k##name, Runtime::RUNTIME, #name, \
10806 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010807
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010808
10809#define I(name, number_of_args, result_size) \
10810 { Runtime::kInline##name, Runtime::INLINE, \
10811 "_" #name, NULL, number_of_args, result_size },
10812
10813Runtime::Function kIntrinsicFunctions[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010814 RUNTIME_FUNCTION_LIST(F)
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010815 INLINE_FUNCTION_LIST(I)
10816 INLINE_RUNTIME_FUNCTION_LIST(I)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010817};
10818
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010819
lrn@chromium.org303ada72010-10-27 09:33:13 +000010820MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Object* dictionary) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010821 ASSERT(dictionary != NULL);
10822 ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
10823 for (int i = 0; i < kNumFunctions; ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000010824 Object* name_symbol;
10825 { MaybeObject* maybe_name_symbol =
10826 Heap::LookupAsciiSymbol(kIntrinsicFunctions[i].name);
10827 if (!maybe_name_symbol->ToObject(&name_symbol)) return maybe_name_symbol;
10828 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010829 StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010830 { MaybeObject* maybe_dictionary = string_dictionary->Add(
10831 String::cast(name_symbol),
10832 Smi::FromInt(i),
10833 PropertyDetails(NONE, NORMAL));
10834 if (!maybe_dictionary->ToObject(&dictionary)) {
10835 // Non-recoverable failure. Calling code must restart heap
10836 // initialization.
10837 return maybe_dictionary;
10838 }
10839 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010840 }
10841 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010842}
10843
10844
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010845Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
10846 int entry = Heap::intrinsic_function_names()->FindEntry(*name);
10847 if (entry != kNotFound) {
10848 Object* smi_index = Heap::intrinsic_function_names()->ValueAt(entry);
10849 int function_index = Smi::cast(smi_index)->value();
10850 return &(kIntrinsicFunctions[function_index]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010851 }
10852 return NULL;
10853}
10854
10855
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010856Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
10857 return &(kIntrinsicFunctions[static_cast<int>(id)]);
10858}
10859
10860
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010861void Runtime::PerformGC(Object* result) {
10862 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010863 if (failure->IsRetryAfterGC()) {
10864 // Try to do a garbage collection; ignore it if it fails. The C
10865 // entry stub will throw an out-of-memory exception in that case.
whesse@chromium.org4a5224e2010-10-20 12:37:07 +000010866 Heap::CollectGarbage(failure->allocation_space());
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010867 } else {
10868 // Handle last resort GC and make sure to allow future allocations
10869 // to grow the heap without causing GCs (if possible).
10870 Counters::gc_last_resort_from_js.Increment();
ager@chromium.orgab99eea2009-08-25 07:05:41 +000010871 Heap::CollectAllGarbage(false);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010872 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010873}
10874
10875
10876} } // namespace v8::internal