blob: fc1a0232295a73e8b50dc1eea178a9034d9e8b48 [file] [log] [blame]
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001// Copyright 2006-2009 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"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000036#include "compiler.h"
37#include "cpu.h"
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000038#include "dateparser-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000039#include "debug.h"
40#include "execution.h"
41#include "jsregexp.h"
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000042#include "liveedit.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000043#include "parser.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000044#include "platform.h"
45#include "runtime.h"
46#include "scopeinfo.h"
ager@chromium.org7c537e22008-10-16 08:43:32 +000047#include "smart-pointer.h"
ager@chromium.org18ad94b2009-09-02 08:22:29 +000048#include "stub-cache.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000049#include "v8threads.h"
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000050#include "string-search.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000051
kasperl@chromium.org71affb52009-05-26 05:44:31 +000052namespace v8 {
53namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000054
55
ager@chromium.org3e875802009-06-29 08:26:34 +000056#define RUNTIME_ASSERT(value) \
57 if (!(value)) return Top::ThrowIllegalOperation();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000058
59// Cast the given object to a value of the specified type and store
60// it in a variable with the given name. If the object is not of the
61// expected type call IllegalOperation and return.
62#define CONVERT_CHECKED(Type, name, obj) \
63 RUNTIME_ASSERT(obj->Is##Type()); \
64 Type* name = Type::cast(obj);
65
66#define CONVERT_ARG_CHECKED(Type, name, index) \
67 RUNTIME_ASSERT(args[index]->Is##Type()); \
68 Handle<Type> name = args.at<Type>(index);
69
kasper.lundbd3ec4e2008-07-09 11:06:54 +000070// Cast the given object to a boolean and store it in a variable with
71// the given name. If the object is not a boolean call IllegalOperation
72// and return.
73#define CONVERT_BOOLEAN_CHECKED(name, obj) \
74 RUNTIME_ASSERT(obj->IsBoolean()); \
75 bool name = (obj)->IsTrue();
76
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000077// Cast the given object to a Smi and store its value in an int variable
78// with the given name. If the object is not a Smi call IllegalOperation
79// and return.
80#define CONVERT_SMI_CHECKED(name, obj) \
81 RUNTIME_ASSERT(obj->IsSmi()); \
82 int name = Smi::cast(obj)->value();
83
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000084// Cast the given object to a double and store it in a variable with
85// the given name. If the object is not a number (as opposed to
86// the number not-a-number) call IllegalOperation and return.
87#define CONVERT_DOUBLE_CHECKED(name, obj) \
88 RUNTIME_ASSERT(obj->IsNumber()); \
89 double name = (obj)->Number();
90
91// Call the specified converter on the object *comand store the result in
92// a variable of the specified type with the given name. If the
93// object is not a Number call IllegalOperation and return.
94#define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \
95 RUNTIME_ASSERT(obj->IsNumber()); \
96 type name = NumberTo##Type(obj);
97
98// Non-reentrant string buffer for efficient general use in this file.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +000099static StaticResource<StringInputBuffer> runtime_string_input_buffer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000100
101
lrn@chromium.org303ada72010-10-27 09:33:13 +0000102MUST_USE_RESULT static MaybeObject* DeepCopyBoilerplate(JSObject* boilerplate) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000103 StackLimitCheck check;
104 if (check.HasOverflowed()) return Top::StackOverflow();
105
lrn@chromium.org303ada72010-10-27 09:33:13 +0000106 Object* result;
107 { MaybeObject* maybe_result = Heap::CopyJSObject(boilerplate);
108 if (!maybe_result->ToObject(&result)) return maybe_result;
109 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000110 JSObject* copy = JSObject::cast(result);
111
112 // Deep copy local properties.
113 if (copy->HasFastProperties()) {
114 FixedArray* properties = copy->properties();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000115 for (int i = 0; i < properties->length(); i++) {
116 Object* value = properties->get(i);
117 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000118 JSObject* js_object = JSObject::cast(value);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000119 { MaybeObject* maybe_result = DeepCopyBoilerplate(js_object);
120 if (!maybe_result->ToObject(&result)) return maybe_result;
121 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000122 properties->set(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000123 }
124 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000125 int nof = copy->map()->inobject_properties();
126 for (int i = 0; i < nof; i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000127 Object* value = copy->InObjectPropertyAt(i);
128 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000129 JSObject* js_object = JSObject::cast(value);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000130 { MaybeObject* maybe_result = DeepCopyBoilerplate(js_object);
131 if (!maybe_result->ToObject(&result)) return maybe_result;
132 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000133 copy->InObjectPropertyAtPut(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000134 }
135 }
136 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000137 { MaybeObject* maybe_result =
138 Heap::AllocateFixedArray(copy->NumberOfLocalProperties(NONE));
139 if (!maybe_result->ToObject(&result)) return maybe_result;
140 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000141 FixedArray* names = FixedArray::cast(result);
142 copy->GetLocalPropertyNames(names, 0);
143 for (int i = 0; i < names->length(); i++) {
144 ASSERT(names->get(i)->IsString());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000145 String* key_string = String::cast(names->get(i));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000146 PropertyAttributes attributes =
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000147 copy->GetLocalPropertyAttribute(key_string);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000148 // Only deep copy fields from the object literal expression.
149 // In particular, don't try to copy the length attribute of
150 // an array.
151 if (attributes != NONE) continue;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000152 Object* value =
153 copy->GetProperty(key_string, &attributes)->ToObjectUnchecked();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000154 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000155 JSObject* js_object = JSObject::cast(value);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000156 { MaybeObject* maybe_result = DeepCopyBoilerplate(js_object);
157 if (!maybe_result->ToObject(&result)) return maybe_result;
158 }
159 { MaybeObject* maybe_result =
160 copy->SetProperty(key_string, result, NONE);
161 if (!maybe_result->ToObject(&result)) return maybe_result;
162 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000163 }
164 }
165 }
166
167 // Deep copy local elements.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000168 // Pixel elements cannot be created using an object literal.
ager@chromium.org3811b432009-10-28 14:53:37 +0000169 ASSERT(!copy->HasPixelElements() && !copy->HasExternalArrayElements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000170 switch (copy->GetElementsKind()) {
171 case JSObject::FAST_ELEMENTS: {
172 FixedArray* elements = FixedArray::cast(copy->elements());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000173 if (elements->map() == Heap::fixed_cow_array_map()) {
174 Counters::cow_arrays_created_runtime.Increment();
175#ifdef DEBUG
176 for (int i = 0; i < elements->length(); i++) {
177 ASSERT(!elements->get(i)->IsJSObject());
178 }
179#endif
180 } else {
181 for (int i = 0; i < elements->length(); i++) {
182 Object* value = elements->get(i);
183 if (value->IsJSObject()) {
184 JSObject* js_object = JSObject::cast(value);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000185 { MaybeObject* maybe_result = DeepCopyBoilerplate(js_object);
186 if (!maybe_result->ToObject(&result)) return maybe_result;
187 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000188 elements->set(i, result);
189 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000190 }
191 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000192 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000193 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000194 case JSObject::DICTIONARY_ELEMENTS: {
195 NumberDictionary* element_dictionary = copy->element_dictionary();
196 int capacity = element_dictionary->Capacity();
197 for (int i = 0; i < capacity; i++) {
198 Object* k = element_dictionary->KeyAt(i);
199 if (element_dictionary->IsKey(k)) {
200 Object* value = element_dictionary->ValueAt(i);
201 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000202 JSObject* js_object = JSObject::cast(value);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000203 { MaybeObject* maybe_result = DeepCopyBoilerplate(js_object);
204 if (!maybe_result->ToObject(&result)) return maybe_result;
205 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000206 element_dictionary->ValueAtPut(i, result);
207 }
208 }
209 }
210 break;
211 }
212 default:
213 UNREACHABLE();
214 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000215 }
216 return copy;
217}
218
219
lrn@chromium.org303ada72010-10-27 09:33:13 +0000220static MaybeObject* Runtime_CloneLiteralBoilerplate(Arguments args) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000221 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
222 return DeepCopyBoilerplate(boilerplate);
223}
224
225
lrn@chromium.org303ada72010-10-27 09:33:13 +0000226static MaybeObject* Runtime_CloneShallowLiteralBoilerplate(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000227 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000228 return Heap::CopyJSObject(boilerplate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000229}
230
231
ager@chromium.org236ad962008-09-25 09:45:57 +0000232static Handle<Map> ComputeObjectLiteralMap(
233 Handle<Context> context,
234 Handle<FixedArray> constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000235 bool* is_result_from_cache) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000236 int properties_length = constant_properties->length();
237 int number_of_properties = properties_length / 2;
ager@chromium.org236ad962008-09-25 09:45:57 +0000238 if (FLAG_canonicalize_object_literal_maps) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000239 // Check that there are only symbols and array indices among keys.
ager@chromium.org236ad962008-09-25 09:45:57 +0000240 int number_of_symbol_keys = 0;
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000241 for (int p = 0; p != properties_length; p += 2) {
242 Object* key = constant_properties->get(p);
243 uint32_t element_index = 0;
244 if (key->IsSymbol()) {
245 number_of_symbol_keys++;
246 } else if (key->ToArrayIndex(&element_index)) {
247 // An index key does not require space in the property backing store.
248 number_of_properties--;
249 } else {
250 // Bail out as a non-symbol non-index key makes caching impossible.
251 // ASSERT to make sure that the if condition after the loop is false.
252 ASSERT(number_of_symbol_keys != number_of_properties);
253 break;
254 }
ager@chromium.org236ad962008-09-25 09:45:57 +0000255 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000256 // If we only have symbols and array indices among keys then we can
257 // use the map cache in the global context.
ager@chromium.org236ad962008-09-25 09:45:57 +0000258 const int kMaxKeys = 10;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000259 if ((number_of_symbol_keys == number_of_properties) &&
260 (number_of_symbol_keys < kMaxKeys)) {
ager@chromium.org236ad962008-09-25 09:45:57 +0000261 // Create the fixed array with the key.
262 Handle<FixedArray> keys = Factory::NewFixedArray(number_of_symbol_keys);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000263 if (number_of_symbol_keys > 0) {
264 int index = 0;
265 for (int p = 0; p < properties_length; p += 2) {
266 Object* key = constant_properties->get(p);
267 if (key->IsSymbol()) {
268 keys->set(index++, key);
269 }
270 }
271 ASSERT(index == number_of_symbol_keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000272 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000273 *is_result_from_cache = true;
ager@chromium.org236ad962008-09-25 09:45:57 +0000274 return Factory::ObjectLiteralMapFromCache(context, keys);
275 }
276 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000277 *is_result_from_cache = false;
ager@chromium.org32912102009-01-16 10:38:43 +0000278 return Factory::CopyMap(
279 Handle<Map>(context->object_function()->initial_map()),
280 number_of_properties);
ager@chromium.org236ad962008-09-25 09:45:57 +0000281}
282
283
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000284static Handle<Object> CreateLiteralBoilerplate(
285 Handle<FixedArray> literals,
286 Handle<FixedArray> constant_properties);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000287
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000288
289static Handle<Object> CreateObjectLiteralBoilerplate(
290 Handle<FixedArray> literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000291 Handle<FixedArray> constant_properties,
292 bool should_have_fast_elements) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000293 // Get the global context from the literals array. This is the
294 // context in which the function was created and we use the object
295 // function from this context to create the object literal. We do
296 // not use the object function from the current global context
297 // because this might be the object function from another context
298 // which we should not have access to.
ager@chromium.org236ad962008-09-25 09:45:57 +0000299 Handle<Context> context =
300 Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals));
301
302 bool is_result_from_cache;
303 Handle<Map> map = ComputeObjectLiteralMap(context,
304 constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000305 &is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000306
ager@chromium.org236ad962008-09-25 09:45:57 +0000307 Handle<JSObject> boilerplate = Factory::NewJSObjectFromMap(map);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000308
309 // Normalize the elements of the boilerplate to save space if needed.
310 if (!should_have_fast_elements) NormalizeElements(boilerplate);
311
ager@chromium.org32912102009-01-16 10:38:43 +0000312 { // Add the constant properties to the boilerplate.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000313 int length = constant_properties->length();
ager@chromium.org236ad962008-09-25 09:45:57 +0000314 OptimizedObjectForAddingMultipleProperties opt(boilerplate,
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000315 length / 2,
ager@chromium.org236ad962008-09-25 09:45:57 +0000316 !is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000317 for (int index = 0; index < length; index +=2) {
318 Handle<Object> key(constant_properties->get(index+0));
319 Handle<Object> value(constant_properties->get(index+1));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000320 if (value->IsFixedArray()) {
321 // The value contains the constant_properties of a
322 // simple object literal.
323 Handle<FixedArray> array = Handle<FixedArray>::cast(value);
324 value = CreateLiteralBoilerplate(literals, array);
325 if (value.is_null()) return value;
326 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000327 Handle<Object> result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000328 uint32_t element_index = 0;
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000329 if (key->IsSymbol()) {
330 // If key is a symbol it is not an array element.
331 Handle<String> name(String::cast(*key));
332 ASSERT(!name->AsArrayIndex(&element_index));
333 result = SetProperty(boilerplate, name, value, NONE);
334 } else if (key->ToArrayIndex(&element_index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000335 // Array index (uint32).
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000336 result = SetElement(boilerplate, element_index, value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000337 } else {
338 // Non-uint32 number.
339 ASSERT(key->IsNumber());
340 double num = key->Number();
341 char arr[100];
342 Vector<char> buffer(arr, ARRAY_SIZE(arr));
343 const char* str = DoubleToCString(num, buffer);
344 Handle<String> name = Factory::NewStringFromAscii(CStrVector(str));
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000345 result = SetProperty(boilerplate, name, value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000346 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000347 // If setting the property on the boilerplate throws an
348 // exception, the exception is converted to an empty handle in
349 // the handle based operations. In that case, we need to
350 // convert back to an exception.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000351 if (result.is_null()) return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000352 }
353 }
354
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000355 return boilerplate;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000356}
357
358
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000359static Handle<Object> CreateArrayLiteralBoilerplate(
360 Handle<FixedArray> literals,
361 Handle<FixedArray> elements) {
362 // Create the JSArray.
363 Handle<JSFunction> constructor(
364 JSFunction::GlobalContextFromLiterals(*literals)->array_function());
365 Handle<Object> object = Factory::NewJSObject(constructor);
366
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000367 const bool is_cow = (elements->map() == Heap::fixed_cow_array_map());
368 Handle<FixedArray> copied_elements =
369 is_cow ? elements : Factory::CopyFixedArray(elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000370
371 Handle<FixedArray> content = Handle<FixedArray>::cast(copied_elements);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000372 if (is_cow) {
373#ifdef DEBUG
374 // Copy-on-write arrays must be shallow (and simple).
375 for (int i = 0; i < content->length(); i++) {
376 ASSERT(!content->get(i)->IsFixedArray());
377 }
378#endif
379 } else {
380 for (int i = 0; i < content->length(); i++) {
381 if (content->get(i)->IsFixedArray()) {
382 // The value contains the constant_properties of a
383 // simple object literal.
384 Handle<FixedArray> fa(FixedArray::cast(content->get(i)));
385 Handle<Object> result =
386 CreateLiteralBoilerplate(literals, fa);
387 if (result.is_null()) return result;
388 content->set(i, *result);
389 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000390 }
391 }
392
393 // Set the elements.
394 Handle<JSArray>::cast(object)->SetContent(*content);
395 return object;
396}
397
398
399static Handle<Object> CreateLiteralBoilerplate(
400 Handle<FixedArray> literals,
401 Handle<FixedArray> array) {
402 Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
403 switch (CompileTimeValue::GetType(array)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000404 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
405 return CreateObjectLiteralBoilerplate(literals, elements, true);
406 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
407 return CreateObjectLiteralBoilerplate(literals, elements, false);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000408 case CompileTimeValue::ARRAY_LITERAL:
409 return CreateArrayLiteralBoilerplate(literals, elements);
410 default:
411 UNREACHABLE();
412 return Handle<Object>::null();
413 }
414}
415
416
lrn@chromium.org303ada72010-10-27 09:33:13 +0000417static MaybeObject* Runtime_CreateArrayLiteralBoilerplate(Arguments args) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000418 // Takes a FixedArray of elements containing the literal elements of
419 // the array literal and produces JSArray with those elements.
420 // Additionally takes the literals array of the surrounding function
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000421 // which contains the context from which to get the Array function
422 // to use for creating the array literal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000423 HandleScope scope;
424 ASSERT(args.length() == 3);
425 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
426 CONVERT_SMI_CHECKED(literals_index, args[1]);
427 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000428
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000429 Handle<Object> object = CreateArrayLiteralBoilerplate(literals, elements);
430 if (object.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000431
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000432 // Update the functions literal and return the boilerplate.
433 literals->set(literals_index, *object);
434 return *object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000435}
436
437
lrn@chromium.org303ada72010-10-27 09:33:13 +0000438static MaybeObject* Runtime_CreateObjectLiteral(Arguments args) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000439 HandleScope scope;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000440 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000441 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
442 CONVERT_SMI_CHECKED(literals_index, args[1]);
443 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000444 CONVERT_SMI_CHECKED(fast_elements, args[3]);
445 bool should_have_fast_elements = fast_elements == 1;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000446
447 // Check if boilerplate exists. If not, create it first.
448 Handle<Object> boilerplate(literals->get(literals_index));
449 if (*boilerplate == Heap::undefined_value()) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000450 boilerplate = CreateObjectLiteralBoilerplate(literals,
451 constant_properties,
452 should_have_fast_elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000453 if (boilerplate.is_null()) return Failure::Exception();
454 // Update the functions literal and return the boilerplate.
455 literals->set(literals_index, *boilerplate);
456 }
457 return DeepCopyBoilerplate(JSObject::cast(*boilerplate));
458}
459
460
lrn@chromium.org303ada72010-10-27 09:33:13 +0000461static MaybeObject* Runtime_CreateObjectLiteralShallow(Arguments args) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000462 HandleScope scope;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000463 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000464 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
465 CONVERT_SMI_CHECKED(literals_index, args[1]);
466 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000467 CONVERT_SMI_CHECKED(fast_elements, args[3]);
468 bool should_have_fast_elements = fast_elements == 1;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000469
470 // Check if boilerplate exists. If not, create it first.
471 Handle<Object> boilerplate(literals->get(literals_index));
472 if (*boilerplate == Heap::undefined_value()) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000473 boilerplate = CreateObjectLiteralBoilerplate(literals,
474 constant_properties,
475 should_have_fast_elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000476 if (boilerplate.is_null()) return Failure::Exception();
477 // Update the functions literal and return the boilerplate.
478 literals->set(literals_index, *boilerplate);
479 }
480 return Heap::CopyJSObject(JSObject::cast(*boilerplate));
481}
482
483
lrn@chromium.org303ada72010-10-27 09:33:13 +0000484static MaybeObject* Runtime_CreateArrayLiteral(Arguments args) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000485 HandleScope scope;
486 ASSERT(args.length() == 3);
487 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
488 CONVERT_SMI_CHECKED(literals_index, args[1]);
489 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
490
491 // Check if boilerplate exists. If not, create it first.
492 Handle<Object> boilerplate(literals->get(literals_index));
493 if (*boilerplate == Heap::undefined_value()) {
494 boilerplate = CreateArrayLiteralBoilerplate(literals, elements);
495 if (boilerplate.is_null()) return Failure::Exception();
496 // Update the functions literal and return the boilerplate.
497 literals->set(literals_index, *boilerplate);
498 }
499 return DeepCopyBoilerplate(JSObject::cast(*boilerplate));
500}
501
502
lrn@chromium.org303ada72010-10-27 09:33:13 +0000503static MaybeObject* Runtime_CreateArrayLiteralShallow(Arguments args) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000504 HandleScope scope;
505 ASSERT(args.length() == 3);
506 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
507 CONVERT_SMI_CHECKED(literals_index, args[1]);
508 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
509
510 // Check if boilerplate exists. If not, create it first.
511 Handle<Object> boilerplate(literals->get(literals_index));
512 if (*boilerplate == Heap::undefined_value()) {
513 boilerplate = CreateArrayLiteralBoilerplate(literals, elements);
514 if (boilerplate.is_null()) return Failure::Exception();
515 // Update the functions literal and return the boilerplate.
516 literals->set(literals_index, *boilerplate);
517 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000518 if (JSObject::cast(*boilerplate)->elements()->map() ==
519 Heap::fixed_cow_array_map()) {
520 Counters::cow_arrays_created_runtime.Increment();
521 }
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000522 return Heap::CopyJSObject(JSObject::cast(*boilerplate));
523}
524
525
lrn@chromium.org303ada72010-10-27 09:33:13 +0000526static MaybeObject* Runtime_CreateCatchExtensionObject(Arguments args) {
ager@chromium.org32912102009-01-16 10:38:43 +0000527 ASSERT(args.length() == 2);
528 CONVERT_CHECKED(String, key, args[0]);
529 Object* value = args[1];
530 // Create a catch context extension object.
531 JSFunction* constructor =
532 Top::context()->global_context()->context_extension_function();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000533 Object* object;
534 { MaybeObject* maybe_object = Heap::AllocateJSObject(constructor);
535 if (!maybe_object->ToObject(&object)) return maybe_object;
536 }
ager@chromium.org32912102009-01-16 10:38:43 +0000537 // Assign the exception value to the catch variable and make sure
538 // that the catch variable is DontDelete.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000539 { MaybeObject* maybe_value =
540 JSObject::cast(object)->SetProperty(key, value, DONT_DELETE);
541 if (!maybe_value->ToObject(&value)) return maybe_value;
542 }
ager@chromium.org32912102009-01-16 10:38:43 +0000543 return object;
544}
545
546
lrn@chromium.org303ada72010-10-27 09:33:13 +0000547static MaybeObject* Runtime_ClassOf(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000548 NoHandleAllocation ha;
549 ASSERT(args.length() == 1);
550 Object* obj = args[0];
551 if (!obj->IsJSObject()) return Heap::null_value();
552 return JSObject::cast(obj)->class_name();
553}
554
ager@chromium.org7c537e22008-10-16 08:43:32 +0000555
lrn@chromium.org303ada72010-10-27 09:33:13 +0000556static MaybeObject* Runtime_IsInPrototypeChain(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000557 NoHandleAllocation ha;
558 ASSERT(args.length() == 2);
559 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
560 Object* O = args[0];
561 Object* V = args[1];
562 while (true) {
563 Object* prototype = V->GetPrototype();
564 if (prototype->IsNull()) return Heap::false_value();
565 if (O == prototype) return Heap::true_value();
566 V = prototype;
567 }
568}
569
570
ager@chromium.org9085a012009-05-11 19:22:57 +0000571// Inserts an object as the hidden prototype of another object.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000572static MaybeObject* Runtime_SetHiddenPrototype(Arguments args) {
ager@chromium.org9085a012009-05-11 19:22:57 +0000573 NoHandleAllocation ha;
574 ASSERT(args.length() == 2);
575 CONVERT_CHECKED(JSObject, jsobject, args[0]);
576 CONVERT_CHECKED(JSObject, proto, args[1]);
577
578 // Sanity checks. The old prototype (that we are replacing) could
579 // theoretically be null, but if it is not null then check that we
580 // didn't already install a hidden prototype here.
581 RUNTIME_ASSERT(!jsobject->GetPrototype()->IsHeapObject() ||
582 !HeapObject::cast(jsobject->GetPrototype())->map()->is_hidden_prototype());
583 RUNTIME_ASSERT(!proto->map()->is_hidden_prototype());
584
585 // Allocate up front before we start altering state in case we get a GC.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000586 Object* map_or_failure;
587 { MaybeObject* maybe_map_or_failure = proto->map()->CopyDropTransitions();
588 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
589 return maybe_map_or_failure;
590 }
591 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000592 Map* new_proto_map = Map::cast(map_or_failure);
593
lrn@chromium.org303ada72010-10-27 09:33:13 +0000594 { MaybeObject* maybe_map_or_failure = jsobject->map()->CopyDropTransitions();
595 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
596 return maybe_map_or_failure;
597 }
598 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000599 Map* new_map = Map::cast(map_or_failure);
600
601 // Set proto's prototype to be the old prototype of the object.
602 new_proto_map->set_prototype(jsobject->GetPrototype());
603 proto->set_map(new_proto_map);
604 new_proto_map->set_is_hidden_prototype();
605
606 // Set the object's prototype to proto.
607 new_map->set_prototype(proto);
608 jsobject->set_map(new_map);
609
610 return Heap::undefined_value();
611}
612
613
lrn@chromium.org303ada72010-10-27 09:33:13 +0000614static MaybeObject* Runtime_IsConstructCall(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000615 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +0000616 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000617 JavaScriptFrameIterator it;
618 return Heap::ToBoolean(it.frame()->IsConstructor());
619}
620
621
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000622// Recursively traverses hidden prototypes if property is not found
623static void GetOwnPropertyImplementation(JSObject* obj,
624 String* name,
625 LookupResult* result) {
626 obj->LocalLookupRealNamedProperty(name, result);
627
628 if (!result->IsProperty()) {
629 Object* proto = obj->GetPrototype();
630 if (proto->IsJSObject() &&
631 JSObject::cast(proto)->map()->is_hidden_prototype())
632 GetOwnPropertyImplementation(JSObject::cast(proto),
633 name, result);
634 }
635}
636
637
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000638// Enumerator used as indices into the array returned from GetOwnProperty
639enum PropertyDescriptorIndices {
640 IS_ACCESSOR_INDEX,
641 VALUE_INDEX,
642 GETTER_INDEX,
643 SETTER_INDEX,
644 WRITABLE_INDEX,
645 ENUMERABLE_INDEX,
646 CONFIGURABLE_INDEX,
647 DESCRIPTOR_SIZE
648};
649
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000650// Returns an array with the property description:
651// if args[1] is not a property on args[0]
652// returns undefined
653// if args[1] is a data property on args[0]
654// [false, value, Writeable, Enumerable, Configurable]
655// if args[1] is an accessor on args[0]
656// [true, GetFunction, SetFunction, Enumerable, Configurable]
lrn@chromium.org303ada72010-10-27 09:33:13 +0000657static MaybeObject* Runtime_GetOwnProperty(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000658 ASSERT(args.length() == 2);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000659 HandleScope scope;
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000660 Handle<FixedArray> elms = Factory::NewFixedArray(DESCRIPTOR_SIZE);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000661 Handle<JSArray> desc = Factory::NewJSArrayWithElements(elms);
662 LookupResult result;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000663 CONVERT_ARG_CHECKED(JSObject, obj, 0);
664 CONVERT_ARG_CHECKED(String, name, 1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000665
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000666 // This could be an element.
667 uint32_t index;
668 if (name->AsArrayIndex(&index)) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000669 switch (obj->HasLocalElement(index)) {
670 case JSObject::UNDEFINED_ELEMENT:
671 return Heap::undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000672
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000673 case JSObject::STRING_CHARACTER_ELEMENT: {
674 // Special handling of string objects according to ECMAScript 5
675 // 15.5.5.2. Note that this might be a string object with elements
676 // other than the actual string value. This is covered by the
677 // subsequent cases.
678 Handle<JSValue> js_value = Handle<JSValue>::cast(obj);
679 Handle<String> str(String::cast(js_value->value()));
680 Handle<String> substr = SubString(str, index, index+1, NOT_TENURED);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000681
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000682 elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
683 elms->set(VALUE_INDEX, *substr);
684 elms->set(WRITABLE_INDEX, Heap::false_value());
685 elms->set(ENUMERABLE_INDEX, Heap::false_value());
686 elms->set(CONFIGURABLE_INDEX, Heap::false_value());
687 return *desc;
688 }
689
690 case JSObject::INTERCEPTED_ELEMENT:
691 case JSObject::FAST_ELEMENT: {
692 elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
693 Handle<Object> element = GetElement(Handle<Object>(obj), index);
694 elms->set(VALUE_INDEX, *element);
695 elms->set(WRITABLE_INDEX, Heap::true_value());
696 elms->set(ENUMERABLE_INDEX, Heap::true_value());
697 elms->set(CONFIGURABLE_INDEX, Heap::true_value());
698 return *desc;
699 }
700
701 case JSObject::DICTIONARY_ELEMENT: {
702 NumberDictionary* dictionary = obj->element_dictionary();
703 int entry = dictionary->FindEntry(index);
704 ASSERT(entry != NumberDictionary::kNotFound);
705 PropertyDetails details = dictionary->DetailsAt(entry);
706 switch (details.type()) {
707 case CALLBACKS: {
708 // This is an accessor property with getter and/or setter.
709 FixedArray* callbacks =
710 FixedArray::cast(dictionary->ValueAt(entry));
711 elms->set(IS_ACCESSOR_INDEX, Heap::true_value());
712 elms->set(GETTER_INDEX, callbacks->get(0));
713 elms->set(SETTER_INDEX, callbacks->get(1));
714 break;
715 }
716 case NORMAL:
717 // This is a data property.
718 elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
719 elms->set(VALUE_INDEX, dictionary->ValueAt(entry));
720 elms->set(WRITABLE_INDEX, Heap::ToBoolean(!details.IsReadOnly()));
721 break;
722 default:
723 UNREACHABLE();
724 break;
725 }
726 elms->set(ENUMERABLE_INDEX, Heap::ToBoolean(!details.IsDontEnum()));
727 elms->set(CONFIGURABLE_INDEX, Heap::ToBoolean(!details.IsDontDelete()));
728 return *desc;
729 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000730 }
731 }
732
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000733 // Use recursive implementation to also traverse hidden prototypes
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000734 GetOwnPropertyImplementation(*obj, *name, &result);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000735
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000736 if (!result.IsProperty()) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000737 return Heap::undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000738 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000739 if (result.type() == CALLBACKS) {
740 Object* structure = result.GetCallbackObject();
ager@chromium.org5c838252010-02-19 08:53:10 +0000741 if (structure->IsProxy() || structure->IsAccessorInfo()) {
742 // Property that is internally implemented as a callback or
743 // an API defined callback.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000744 Object* value;
745 { MaybeObject* maybe_value = obj->GetPropertyWithCallback(
746 *obj, structure, *name, result.holder());
747 if (!maybe_value->ToObject(&value)) return maybe_value;
748 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000749 elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
750 elms->set(VALUE_INDEX, value);
751 elms->set(WRITABLE_INDEX, Heap::ToBoolean(!result.IsReadOnly()));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000752 } else if (structure->IsFixedArray()) {
753 // __defineGetter__/__defineSetter__ callback.
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000754 elms->set(IS_ACCESSOR_INDEX, Heap::true_value());
755 elms->set(GETTER_INDEX, FixedArray::cast(structure)->get(0));
756 elms->set(SETTER_INDEX, FixedArray::cast(structure)->get(1));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000757 } else {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000758 return Heap::undefined_value();
759 }
760 } else {
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000761 elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
762 elms->set(VALUE_INDEX, result.GetLazyValue());
763 elms->set(WRITABLE_INDEX, Heap::ToBoolean(!result.IsReadOnly()));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000764 }
765
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000766 elms->set(ENUMERABLE_INDEX, Heap::ToBoolean(!result.IsDontEnum()));
767 elms->set(CONFIGURABLE_INDEX, Heap::ToBoolean(!result.IsDontDelete()));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000768 return *desc;
769}
770
771
lrn@chromium.org303ada72010-10-27 09:33:13 +0000772static MaybeObject* Runtime_PreventExtensions(Arguments args) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000773 ASSERT(args.length() == 1);
774 CONVERT_CHECKED(JSObject, obj, args[0]);
775 return obj->PreventExtensions();
776}
777
lrn@chromium.org303ada72010-10-27 09:33:13 +0000778static MaybeObject* Runtime_IsExtensible(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000779 ASSERT(args.length() == 1);
780 CONVERT_CHECKED(JSObject, obj, args[0]);
781 return obj->map()->is_extensible() ? Heap::true_value()
782 : Heap::false_value();
783}
784
785
lrn@chromium.org303ada72010-10-27 09:33:13 +0000786static MaybeObject* Runtime_RegExpCompile(Arguments args) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000787 HandleScope scope;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000788 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000789 CONVERT_ARG_CHECKED(JSRegExp, re, 0);
790 CONVERT_ARG_CHECKED(String, pattern, 1);
791 CONVERT_ARG_CHECKED(String, flags, 2);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000792 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags);
793 if (result.is_null()) return Failure::Exception();
794 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000795}
796
797
lrn@chromium.org303ada72010-10-27 09:33:13 +0000798static MaybeObject* Runtime_CreateApiFunction(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000799 HandleScope scope;
800 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000801 CONVERT_ARG_CHECKED(FunctionTemplateInfo, data, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000802 return *Factory::CreateApiFunction(data);
803}
804
805
lrn@chromium.org303ada72010-10-27 09:33:13 +0000806static MaybeObject* Runtime_IsTemplate(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000807 ASSERT(args.length() == 1);
808 Object* arg = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000809 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000810 return Heap::ToBoolean(result);
811}
812
813
lrn@chromium.org303ada72010-10-27 09:33:13 +0000814static MaybeObject* Runtime_GetTemplateField(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000815 ASSERT(args.length() == 2);
816 CONVERT_CHECKED(HeapObject, templ, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000817 CONVERT_CHECKED(Smi, field, args[1]);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000818 int index = field->value();
819 int offset = index * kPointerSize + HeapObject::kHeaderSize;
820 InstanceType type = templ->map()->instance_type();
821 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
822 type == OBJECT_TEMPLATE_INFO_TYPE);
823 RUNTIME_ASSERT(offset > 0);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000824 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000825 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
826 } else {
827 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
828 }
829 return *HeapObject::RawField(templ, offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000830}
831
832
lrn@chromium.org303ada72010-10-27 09:33:13 +0000833static MaybeObject* Runtime_DisableAccessChecks(Arguments args) {
ager@chromium.org870a0b62008-11-04 11:43:05 +0000834 ASSERT(args.length() == 1);
835 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +0000836 Map* old_map = object->map();
837 bool needs_access_checks = old_map->is_access_check_needed();
838 if (needs_access_checks) {
839 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000840 Object* new_map;
841 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
842 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
843 }
ager@chromium.org32912102009-01-16 10:38:43 +0000844
845 Map::cast(new_map)->set_is_access_check_needed(false);
846 object->set_map(Map::cast(new_map));
847 }
ager@chromium.org870a0b62008-11-04 11:43:05 +0000848 return needs_access_checks ? Heap::true_value() : Heap::false_value();
849}
850
851
lrn@chromium.org303ada72010-10-27 09:33:13 +0000852static MaybeObject* Runtime_EnableAccessChecks(Arguments args) {
ager@chromium.org870a0b62008-11-04 11:43:05 +0000853 ASSERT(args.length() == 1);
854 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +0000855 Map* old_map = object->map();
856 if (!old_map->is_access_check_needed()) {
857 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000858 Object* new_map;
859 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
860 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
861 }
ager@chromium.org32912102009-01-16 10:38:43 +0000862
863 Map::cast(new_map)->set_is_access_check_needed(true);
864 object->set_map(Map::cast(new_map));
865 }
ager@chromium.org870a0b62008-11-04 11:43:05 +0000866 return Heap::undefined_value();
867}
868
869
lrn@chromium.org303ada72010-10-27 09:33:13 +0000870static Failure* ThrowRedeclarationError(const char* type, Handle<String> name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000871 HandleScope scope;
872 Handle<Object> type_handle = Factory::NewStringFromAscii(CStrVector(type));
873 Handle<Object> args[2] = { type_handle, name };
874 Handle<Object> error =
875 Factory::NewTypeError("redeclaration", HandleVector(args, 2));
876 return Top::Throw(*error);
877}
878
879
lrn@chromium.org303ada72010-10-27 09:33:13 +0000880static MaybeObject* Runtime_DeclareGlobals(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000881 HandleScope scope;
882 Handle<GlobalObject> global = Handle<GlobalObject>(Top::context()->global());
883
ager@chromium.org3811b432009-10-28 14:53:37 +0000884 Handle<Context> context = args.at<Context>(0);
885 CONVERT_ARG_CHECKED(FixedArray, pairs, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000886 bool is_eval = Smi::cast(args[2])->value() == 1;
887
888 // Compute the property attributes. According to ECMA-262, section
889 // 13, page 71, the property must be read-only and
890 // non-deletable. However, neither SpiderMonkey nor KJS creates the
891 // property as read-only, so we don't either.
892 PropertyAttributes base = is_eval ? NONE : DONT_DELETE;
893
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000894 // Traverse the name/value pairs and set the properties.
895 int length = pairs->length();
896 for (int i = 0; i < length; i += 2) {
897 HandleScope scope;
898 Handle<String> name(String::cast(pairs->get(i)));
899 Handle<Object> value(pairs->get(i + 1));
900
901 // We have to declare a global const property. To capture we only
902 // assign to it when evaluating the assignment for "const x =
903 // <expr>" the initial value is the hole.
904 bool is_const_property = value->IsTheHole();
905
906 if (value->IsUndefined() || is_const_property) {
907 // Lookup the property in the global object, and don't set the
908 // value of the variable if the property is already there.
909 LookupResult lookup;
910 global->Lookup(*name, &lookup);
911 if (lookup.IsProperty()) {
912 // Determine if the property is local by comparing the holder
913 // against the global object. The information will be used to
914 // avoid throwing re-declaration errors when declaring
915 // variables or constants that exist in the prototype chain.
916 bool is_local = (*global == lookup.holder());
917 // Get the property attributes and determine if the property is
918 // read-only.
919 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
920 bool is_read_only = (attributes & READ_ONLY) != 0;
921 if (lookup.type() == INTERCEPTOR) {
922 // If the interceptor says the property is there, we
923 // just return undefined without overwriting the property.
924 // Otherwise, we continue to setting the property.
925 if (attributes != ABSENT) {
926 // Check if the existing property conflicts with regards to const.
927 if (is_local && (is_read_only || is_const_property)) {
928 const char* type = (is_read_only) ? "const" : "var";
929 return ThrowRedeclarationError(type, name);
930 };
931 // The property already exists without conflicting: Go to
932 // the next declaration.
933 continue;
934 }
935 // Fall-through and introduce the absent property by using
936 // SetProperty.
937 } else {
938 if (is_local && (is_read_only || is_const_property)) {
939 const char* type = (is_read_only) ? "const" : "var";
940 return ThrowRedeclarationError(type, name);
941 }
942 // The property already exists without conflicting: Go to
943 // the next declaration.
944 continue;
945 }
946 }
947 } else {
948 // Copy the function and update its context. Use it as value.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000949 Handle<SharedFunctionInfo> shared =
950 Handle<SharedFunctionInfo>::cast(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000951 Handle<JSFunction> function =
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000952 Factory::NewFunctionFromSharedFunctionInfo(shared, context, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000953 value = function;
954 }
955
956 LookupResult lookup;
957 global->LocalLookup(*name, &lookup);
958
959 PropertyAttributes attributes = is_const_property
960 ? static_cast<PropertyAttributes>(base | READ_ONLY)
961 : base;
962
963 if (lookup.IsProperty()) {
964 // There's a local property that we need to overwrite because
965 // we're either declaring a function or there's an interceptor
966 // that claims the property is absent.
967
968 // Check for conflicting re-declarations. We cannot have
969 // conflicting types in case of intercepted properties because
970 // they are absent.
971 if (lookup.type() != INTERCEPTOR &&
972 (lookup.IsReadOnly() || is_const_property)) {
973 const char* type = (lookup.IsReadOnly()) ? "const" : "var";
974 return ThrowRedeclarationError(type, name);
975 }
976 SetProperty(global, name, value, attributes);
977 } else {
978 // If a property with this name does not already exist on the
979 // global object add the property locally. We take special
980 // precautions to always add it as a local property even in case
981 // of callbacks in the prototype chain (this rules out using
982 // SetProperty). Also, we must use the handle-based version to
983 // avoid GC issues.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000984 IgnoreAttributesAndSetLocalProperty(global, name, value, attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000985 }
986 }
ager@chromium.org7c537e22008-10-16 08:43:32 +0000987
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000988 return Heap::undefined_value();
989}
990
991
lrn@chromium.org303ada72010-10-27 09:33:13 +0000992static MaybeObject* Runtime_DeclareContextSlot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000993 HandleScope scope;
ager@chromium.org7c537e22008-10-16 08:43:32 +0000994 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000995
ager@chromium.org7c537e22008-10-16 08:43:32 +0000996 CONVERT_ARG_CHECKED(Context, context, 0);
997 Handle<String> name(String::cast(args[1]));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000998 PropertyAttributes mode =
ager@chromium.org7c537e22008-10-16 08:43:32 +0000999 static_cast<PropertyAttributes>(Smi::cast(args[2])->value());
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001000 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001001 Handle<Object> initial_value(args[3]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001002
1003 // Declarations are always done in the function context.
1004 context = Handle<Context>(context->fcontext());
1005
1006 int index;
1007 PropertyAttributes attributes;
1008 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001009 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001010 context->Lookup(name, flags, &index, &attributes);
1011
1012 if (attributes != ABSENT) {
1013 // The name was declared before; check for conflicting
1014 // re-declarations: This is similar to the code in parser.cc in
1015 // the AstBuildingParser::Declare function.
1016 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
1017 // Functions are not read-only.
1018 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
1019 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
1020 return ThrowRedeclarationError(type, name);
1021 }
1022
1023 // Initialize it if necessary.
1024 if (*initial_value != NULL) {
1025 if (index >= 0) {
1026 // The variable or constant context slot should always be in
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001027 // the function context or the arguments object.
1028 if (holder->IsContext()) {
1029 ASSERT(holder.is_identical_to(context));
1030 if (((attributes & READ_ONLY) == 0) ||
1031 context->get(index)->IsTheHole()) {
1032 context->set(index, *initial_value);
1033 }
1034 } else {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001035 // The holder is an arguments object.
1036 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
1037 SetElement(arguments, index, initial_value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001038 }
1039 } else {
1040 // Slow case: The property is not in the FixedArray part of the context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001041 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001042 SetProperty(context_ext, name, initial_value, mode);
1043 }
1044 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001045
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001046 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001047 // The property is not in the function context. It needs to be
1048 // "declared" in the function context's extension context, or in the
1049 // global context.
1050 Handle<JSObject> context_ext;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001051 if (context->has_extension()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001052 // The function context's extension context exists - use it.
1053 context_ext = Handle<JSObject>(context->extension());
1054 } else {
1055 // The function context's extension context does not exists - allocate
1056 // it.
1057 context_ext = Factory::NewJSObject(Top::context_extension_function());
1058 // And store it in the extension slot.
1059 context->set_extension(*context_ext);
1060 }
1061 ASSERT(*context_ext != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001062
ager@chromium.org7c537e22008-10-16 08:43:32 +00001063 // Declare the property by setting it to the initial value if provided,
1064 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
1065 // constant declarations).
1066 ASSERT(!context_ext->HasLocalProperty(*name));
1067 Handle<Object> value(Heap::undefined_value());
1068 if (*initial_value != NULL) value = initial_value;
1069 SetProperty(context_ext, name, value, mode);
1070 ASSERT(context_ext->GetLocalPropertyAttribute(*name) == mode);
1071 }
1072
1073 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001074}
1075
1076
lrn@chromium.org303ada72010-10-27 09:33:13 +00001077static MaybeObject* Runtime_InitializeVarGlobal(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001078 NoHandleAllocation nha;
1079
1080 // Determine if we need to assign to the variable if it already
1081 // exists (based on the number of arguments).
1082 RUNTIME_ASSERT(args.length() == 1 || args.length() == 2);
1083 bool assign = args.length() == 2;
1084
1085 CONVERT_ARG_CHECKED(String, name, 0);
1086 GlobalObject* global = Top::context()->global();
1087
1088 // According to ECMA-262, section 12.2, page 62, the property must
1089 // not be deletable.
1090 PropertyAttributes attributes = DONT_DELETE;
1091
1092 // Lookup the property locally in the global object. If it isn't
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001093 // there, there is a property with this name in the prototype chain.
1094 // We follow Safari and Firefox behavior and only set the property
1095 // locally if there is an explicit initialization value that we have
1096 // to assign to the property. When adding the property we take
1097 // special precautions to always add it as a local property even in
1098 // case of callbacks in the prototype chain (this rules out using
1099 // SetProperty). We have IgnoreAttributesAndSetLocalProperty for
1100 // this.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001101 // Note that objects can have hidden prototypes, so we need to traverse
1102 // the whole chain of hidden prototypes to do a 'local' lookup.
1103 JSObject* real_holder = global;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001104 LookupResult lookup;
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001105 while (true) {
1106 real_holder->LocalLookup(*name, &lookup);
1107 if (lookup.IsProperty()) {
1108 // Determine if this is a redeclaration of something read-only.
1109 if (lookup.IsReadOnly()) {
1110 // If we found readonly property on one of hidden prototypes,
1111 // just shadow it.
1112 if (real_holder != Top::context()->global()) break;
1113 return ThrowRedeclarationError("const", name);
1114 }
1115
1116 // Determine if this is a redeclaration of an intercepted read-only
1117 // property and figure out if the property exists at all.
1118 bool found = true;
1119 PropertyType type = lookup.type();
1120 if (type == INTERCEPTOR) {
1121 HandleScope handle_scope;
1122 Handle<JSObject> holder(real_holder);
1123 PropertyAttributes intercepted = holder->GetPropertyAttribute(*name);
1124 real_holder = *holder;
1125 if (intercepted == ABSENT) {
1126 // The interceptor claims the property isn't there. We need to
1127 // make sure to introduce it.
1128 found = false;
1129 } else if ((intercepted & READ_ONLY) != 0) {
1130 // The property is present, but read-only. Since we're trying to
1131 // overwrite it with a variable declaration we must throw a
1132 // re-declaration error. However if we found readonly property
1133 // on one of hidden prototypes, just shadow it.
1134 if (real_holder != Top::context()->global()) break;
1135 return ThrowRedeclarationError("const", name);
1136 }
1137 }
1138
1139 if (found && !assign) {
1140 // The global property is there and we're not assigning any value
1141 // to it. Just return.
1142 return Heap::undefined_value();
1143 }
1144
1145 // Assign the value (or undefined) to the property.
1146 Object* value = (assign) ? args[1] : Heap::undefined_value();
1147 return real_holder->SetProperty(&lookup, *name, value, attributes);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001148 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001149
1150 Object* proto = real_holder->GetPrototype();
1151 if (!proto->IsJSObject())
1152 break;
1153
1154 if (!JSObject::cast(proto)->map()->is_hidden_prototype())
1155 break;
1156
1157 real_holder = JSObject::cast(proto);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001158 }
1159
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001160 global = Top::context()->global();
1161 if (assign) {
1162 return global->IgnoreAttributesAndSetLocalProperty(*name,
1163 args[1],
1164 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001165 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001166 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001167}
1168
1169
lrn@chromium.org303ada72010-10-27 09:33:13 +00001170static MaybeObject* Runtime_InitializeConstGlobal(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001171 // All constants are declared with an initial value. The name
1172 // of the constant is the first argument and the initial value
1173 // is the second.
1174 RUNTIME_ASSERT(args.length() == 2);
1175 CONVERT_ARG_CHECKED(String, name, 0);
1176 Handle<Object> value = args.at<Object>(1);
1177
1178 // Get the current global object from top.
1179 GlobalObject* global = Top::context()->global();
1180
1181 // According to ECMA-262, section 12.2, page 62, the property must
1182 // not be deletable. Since it's a const, it must be READ_ONLY too.
1183 PropertyAttributes attributes =
1184 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
1185
1186 // Lookup the property locally in the global object. If it isn't
1187 // there, we add the property and take special precautions to always
1188 // add it as a local property even in case of callbacks in the
1189 // prototype chain (this rules out using SetProperty).
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001190 // We use IgnoreAttributesAndSetLocalProperty instead
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001191 LookupResult lookup;
1192 global->LocalLookup(*name, &lookup);
1193 if (!lookup.IsProperty()) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001194 return global->IgnoreAttributesAndSetLocalProperty(*name,
1195 *value,
1196 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001197 }
1198
1199 // Determine if this is a redeclaration of something not
1200 // read-only. In case the result is hidden behind an interceptor we
1201 // need to ask it for the property attributes.
1202 if (!lookup.IsReadOnly()) {
1203 if (lookup.type() != INTERCEPTOR) {
1204 return ThrowRedeclarationError("var", name);
1205 }
1206
1207 PropertyAttributes intercepted = global->GetPropertyAttribute(*name);
1208
1209 // Throw re-declaration error if the intercepted property is present
1210 // but not read-only.
1211 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
1212 return ThrowRedeclarationError("var", name);
1213 }
1214
1215 // Restore global object from context (in case of GC) and continue
1216 // with setting the value because the property is either absent or
1217 // read-only. We also have to do redo the lookup.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001218 HandleScope handle_scope;
1219 Handle<GlobalObject>global(Top::context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001220
1221 // BUG 1213579: Handle the case where we have to set a read-only
1222 // property through an interceptor and only do it if it's
1223 // uninitialized, e.g. the hole. Nirk...
lrn@chromium.org303ada72010-10-27 09:33:13 +00001224 SetProperty(global, name, value, attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001225 return *value;
1226 }
1227
1228 // Set the value, but only we're assigning the initial value to a
1229 // constant. For now, we determine this by checking if the
1230 // current value is the hole.
1231 PropertyType type = lookup.type();
1232 if (type == FIELD) {
1233 FixedArray* properties = global->properties();
1234 int index = lookup.GetFieldIndex();
1235 if (properties->get(index)->IsTheHole()) {
1236 properties->set(index, *value);
1237 }
1238 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001239 if (global->GetNormalizedProperty(&lookup)->IsTheHole()) {
1240 global->SetNormalizedProperty(&lookup, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001241 }
1242 } else {
1243 // Ignore re-initialization of constants that have already been
1244 // assigned a function value.
1245 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
1246 }
1247
1248 // Use the set value as the result of the operation.
1249 return *value;
1250}
1251
1252
lrn@chromium.org303ada72010-10-27 09:33:13 +00001253static MaybeObject* Runtime_InitializeConstContextSlot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001254 HandleScope scope;
1255 ASSERT(args.length() == 3);
1256
1257 Handle<Object> value(args[0]);
1258 ASSERT(!value->IsTheHole());
1259 CONVERT_ARG_CHECKED(Context, context, 1);
1260 Handle<String> name(String::cast(args[2]));
1261
1262 // Initializations are always done in the function context.
1263 context = Handle<Context>(context->fcontext());
1264
1265 int index;
1266 PropertyAttributes attributes;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001267 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001268 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001269 context->Lookup(name, flags, &index, &attributes);
1270
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001271 // In most situations, the property introduced by the const
1272 // declaration should be present in the context extension object.
1273 // However, because declaration and initialization are separate, the
1274 // property might have been deleted (if it was introduced by eval)
1275 // before we reach the initialization point.
1276 //
1277 // Example:
1278 //
1279 // function f() { eval("delete x; const x;"); }
1280 //
1281 // In that case, the initialization behaves like a normal assignment
1282 // to property 'x'.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001283 if (index >= 0) {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001284 // Property was found in a context.
1285 if (holder->IsContext()) {
1286 // The holder cannot be the function context. If it is, there
1287 // should have been a const redeclaration error when declaring
1288 // the const property.
1289 ASSERT(!holder.is_identical_to(context));
1290 if ((attributes & READ_ONLY) == 0) {
1291 Handle<Context>::cast(holder)->set(index, *value);
1292 }
1293 } else {
1294 // The holder is an arguments object.
1295 ASSERT((attributes & READ_ONLY) == 0);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001296 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
1297 SetElement(arguments, index, value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001298 }
1299 return *value;
1300 }
1301
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001302 // The property could not be found, we introduce it in the global
1303 // context.
1304 if (attributes == ABSENT) {
1305 Handle<JSObject> global = Handle<JSObject>(Top::context()->global());
1306 SetProperty(global, name, value, NONE);
1307 return *value;
1308 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001309
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001310 // The property was present in a context extension object.
1311 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001312
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001313 if (*context_ext == context->extension()) {
1314 // This is the property that was introduced by the const
1315 // declaration. Set it if it hasn't been set before. NOTE: We
1316 // cannot use GetProperty() to get the current value as it
1317 // 'unholes' the value.
1318 LookupResult lookup;
1319 context_ext->LocalLookupRealNamedProperty(*name, &lookup);
1320 ASSERT(lookup.IsProperty()); // the property was declared
1321 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
1322
1323 PropertyType type = lookup.type();
1324 if (type == FIELD) {
1325 FixedArray* properties = context_ext->properties();
1326 int index = lookup.GetFieldIndex();
1327 if (properties->get(index)->IsTheHole()) {
1328 properties->set(index, *value);
1329 }
1330 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001331 if (context_ext->GetNormalizedProperty(&lookup)->IsTheHole()) {
1332 context_ext->SetNormalizedProperty(&lookup, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001333 }
1334 } else {
1335 // We should not reach here. Any real, named property should be
1336 // either a field or a dictionary slot.
1337 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001338 }
1339 } else {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001340 // The property was found in a different context extension object.
1341 // Set it if it is not a read-only property.
1342 if ((attributes & READ_ONLY) == 0) {
1343 Handle<Object> set = SetProperty(context_ext, name, value, attributes);
1344 // Setting a property might throw an exception. Exceptions
1345 // are converted to empty handles in handle operations. We
1346 // need to convert back to exceptions here.
1347 if (set.is_null()) {
1348 ASSERT(Top::has_pending_exception());
1349 return Failure::Exception();
1350 }
1351 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001352 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001353
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001354 return *value;
1355}
1356
1357
lrn@chromium.org303ada72010-10-27 09:33:13 +00001358static MaybeObject* Runtime_OptimizeObjectForAddingMultipleProperties(
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001359 Arguments args) {
1360 HandleScope scope;
1361 ASSERT(args.length() == 2);
1362 CONVERT_ARG_CHECKED(JSObject, object, 0);
1363 CONVERT_SMI_CHECKED(properties, args[1]);
1364 if (object->HasFastProperties()) {
1365 NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
1366 }
1367 return *object;
1368}
1369
1370
lrn@chromium.org303ada72010-10-27 09:33:13 +00001371static MaybeObject* Runtime_RegExpExec(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001372 HandleScope scope;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001373 ASSERT(args.length() == 4);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001374 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
1375 CONVERT_ARG_CHECKED(String, subject, 1);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001376 // Due to the way the JS calls are constructed this must be less than the
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001377 // length of a string, i.e. it is always a Smi. We check anyway for security.
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001378 CONVERT_SMI_CHECKED(index, args[2]);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001379 CONVERT_ARG_CHECKED(JSArray, last_match_info, 3);
ager@chromium.org41826e72009-03-30 13:30:57 +00001380 RUNTIME_ASSERT(last_match_info->HasFastElements());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001381 RUNTIME_ASSERT(index >= 0);
1382 RUNTIME_ASSERT(index <= subject->length());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001383 Counters::regexp_entry_runtime.Increment();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001384 Handle<Object> result = RegExpImpl::Exec(regexp,
1385 subject,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001386 index,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001387 last_match_info);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001388 if (result.is_null()) return Failure::Exception();
1389 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001390}
1391
1392
lrn@chromium.org303ada72010-10-27 09:33:13 +00001393static MaybeObject* Runtime_RegExpConstructResult(Arguments args) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001394 ASSERT(args.length() == 3);
1395 CONVERT_SMI_CHECKED(elements_count, args[0]);
1396 if (elements_count > JSArray::kMaxFastElementsLength) {
1397 return Top::ThrowIllegalOperation();
1398 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00001399 Object* new_object;
1400 { MaybeObject* maybe_new_object =
1401 Heap::AllocateFixedArrayWithHoles(elements_count);
1402 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1403 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001404 FixedArray* elements = FixedArray::cast(new_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001405 { MaybeObject* maybe_new_object = Heap::AllocateRaw(JSRegExpResult::kSize,
1406 NEW_SPACE,
1407 OLD_POINTER_SPACE);
1408 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1409 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001410 {
1411 AssertNoAllocation no_gc;
1412 HandleScope scope;
1413 reinterpret_cast<HeapObject*>(new_object)->
1414 set_map(Top::global_context()->regexp_result_map());
1415 }
1416 JSArray* array = JSArray::cast(new_object);
1417 array->set_properties(Heap::empty_fixed_array());
1418 array->set_elements(elements);
1419 array->set_length(Smi::FromInt(elements_count));
1420 // Write in-object properties after the length of the array.
1421 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]);
1422 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]);
1423 return array;
1424}
1425
1426
lrn@chromium.org303ada72010-10-27 09:33:13 +00001427static MaybeObject* Runtime_RegExpCloneResult(Arguments args) {
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00001428 ASSERT(args.length() == 1);
1429 Map* regexp_result_map;
1430 {
1431 AssertNoAllocation no_gc;
1432 HandleScope handles;
1433 regexp_result_map = Top::global_context()->regexp_result_map();
1434 }
1435 if (!args[0]->IsJSArray()) return args[0];
1436
1437 JSArray* result = JSArray::cast(args[0]);
1438 // Arguments to RegExpCloneResult should always be fresh RegExp exec call
1439 // results (either a fresh JSRegExpResult or null).
1440 // If the argument is not a JSRegExpResult, or isn't unmodified, just return
1441 // the argument uncloned.
1442 if (result->map() != regexp_result_map) return result;
1443
1444 // Having the original JSRegExpResult map guarantees that we have
1445 // fast elements and no properties except the two in-object properties.
1446 ASSERT(result->HasFastElements());
1447 ASSERT(result->properties() == Heap::empty_fixed_array());
1448 ASSERT_EQ(2, regexp_result_map->inobject_properties());
1449
lrn@chromium.org303ada72010-10-27 09:33:13 +00001450 Object* new_array_alloc;
1451 { MaybeObject* maybe_new_array_alloc =
1452 Heap::AllocateRaw(JSRegExpResult::kSize, NEW_SPACE, OLD_POINTER_SPACE);
1453 if (!maybe_new_array_alloc->ToObject(&new_array_alloc)) {
1454 return maybe_new_array_alloc;
1455 }
1456 }
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00001457
1458 // Set HeapObject map to JSRegExpResult map.
1459 reinterpret_cast<HeapObject*>(new_array_alloc)->set_map(regexp_result_map);
1460
1461 JSArray* new_array = JSArray::cast(new_array_alloc);
1462
1463 // Copy JSObject properties.
1464 new_array->set_properties(result->properties()); // Empty FixedArray.
1465
1466 // Copy JSObject elements as copy-on-write.
1467 FixedArray* elements = FixedArray::cast(result->elements());
1468 if (elements != Heap::empty_fixed_array()) {
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00001469 elements->set_map(Heap::fixed_cow_array_map());
1470 }
1471 new_array->set_elements(elements);
1472
1473 // Copy JSArray length.
1474 new_array->set_length(result->length());
1475
1476 // Copy JSRegExpResult in-object property fields input and index.
1477 new_array->FastPropertyAtPut(JSRegExpResult::kIndexIndex,
1478 result->FastPropertyAt(
1479 JSRegExpResult::kIndexIndex));
1480 new_array->FastPropertyAtPut(JSRegExpResult::kInputIndex,
1481 result->FastPropertyAt(
1482 JSRegExpResult::kInputIndex));
1483 return new_array;
1484}
1485
1486
lrn@chromium.org303ada72010-10-27 09:33:13 +00001487static MaybeObject* Runtime_RegExpInitializeObject(Arguments args) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00001488 AssertNoAllocation no_alloc;
1489 ASSERT(args.length() == 5);
1490 CONVERT_CHECKED(JSRegExp, regexp, args[0]);
1491 CONVERT_CHECKED(String, source, args[1]);
1492
1493 Object* global = args[2];
1494 if (!global->IsTrue()) global = Heap::false_value();
1495
1496 Object* ignoreCase = args[3];
1497 if (!ignoreCase->IsTrue()) ignoreCase = Heap::false_value();
1498
1499 Object* multiline = args[4];
1500 if (!multiline->IsTrue()) multiline = Heap::false_value();
1501
1502 Map* map = regexp->map();
1503 Object* constructor = map->constructor();
1504 if (constructor->IsJSFunction() &&
1505 JSFunction::cast(constructor)->initial_map() == map) {
1506 // If we still have the original map, set in-object properties directly.
1507 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source);
1508 // TODO(lrn): Consider skipping write barrier on booleans as well.
1509 // Both true and false should be in oldspace at all times.
1510 regexp->InObjectPropertyAtPut(JSRegExp::kGlobalFieldIndex, global);
1511 regexp->InObjectPropertyAtPut(JSRegExp::kIgnoreCaseFieldIndex, ignoreCase);
1512 regexp->InObjectPropertyAtPut(JSRegExp::kMultilineFieldIndex, multiline);
1513 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
1514 Smi::FromInt(0),
1515 SKIP_WRITE_BARRIER);
1516 return regexp;
1517 }
1518
lrn@chromium.org303ada72010-10-27 09:33:13 +00001519 // Map has changed, so use generic, but slower, method. Since these
1520 // properties were all added as DONT_DELETE they must be present and
1521 // normal so no failures can be expected.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001522 PropertyAttributes final =
1523 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
1524 PropertyAttributes writable =
1525 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001526 MaybeObject* result;
1527 result = regexp->IgnoreAttributesAndSetLocalProperty(Heap::source_symbol(),
1528 source,
1529 final);
1530 ASSERT(!result->IsFailure());
1531 result = regexp->IgnoreAttributesAndSetLocalProperty(Heap::global_symbol(),
1532 global,
1533 final);
1534 ASSERT(!result->IsFailure());
1535 result =
1536 regexp->IgnoreAttributesAndSetLocalProperty(Heap::ignore_case_symbol(),
1537 ignoreCase,
1538 final);
1539 ASSERT(!result->IsFailure());
1540 result = regexp->IgnoreAttributesAndSetLocalProperty(Heap::multiline_symbol(),
1541 multiline,
1542 final);
1543 ASSERT(!result->IsFailure());
1544 result =
1545 regexp->IgnoreAttributesAndSetLocalProperty(Heap::last_index_symbol(),
1546 Smi::FromInt(0),
1547 writable);
1548 ASSERT(!result->IsFailure());
1549 USE(result);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001550 return regexp;
1551}
1552
1553
lrn@chromium.org303ada72010-10-27 09:33:13 +00001554static MaybeObject* Runtime_FinishArrayPrototypeSetup(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001555 HandleScope scope;
1556 ASSERT(args.length() == 1);
1557 CONVERT_ARG_CHECKED(JSArray, prototype, 0);
1558 // This is necessary to enable fast checks for absence of elements
1559 // on Array.prototype and below.
1560 prototype->set_elements(Heap::empty_fixed_array());
1561 return Smi::FromInt(0);
1562}
1563
1564
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001565static Handle<JSFunction> InstallBuiltin(Handle<JSObject> holder,
1566 const char* name,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001567 Builtins::Name builtin_name) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001568 Handle<String> key = Factory::LookupAsciiSymbol(name);
1569 Handle<Code> code(Builtins::builtin(builtin_name));
1570 Handle<JSFunction> optimized = Factory::NewFunction(key,
1571 JS_OBJECT_TYPE,
1572 JSObject::kHeaderSize,
1573 code,
1574 false);
1575 optimized->shared()->DontAdaptArguments();
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001576 SetProperty(holder, key, optimized, NONE);
1577 return optimized;
1578}
1579
1580
lrn@chromium.org303ada72010-10-27 09:33:13 +00001581static MaybeObject* Runtime_SpecialArrayFunctions(Arguments args) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001582 HandleScope scope;
1583 ASSERT(args.length() == 1);
1584 CONVERT_ARG_CHECKED(JSObject, holder, 0);
1585
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001586 InstallBuiltin(holder, "pop", Builtins::ArrayPop);
1587 InstallBuiltin(holder, "push", Builtins::ArrayPush);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001588 InstallBuiltin(holder, "shift", Builtins::ArrayShift);
1589 InstallBuiltin(holder, "unshift", Builtins::ArrayUnshift);
1590 InstallBuiltin(holder, "slice", Builtins::ArraySlice);
1591 InstallBuiltin(holder, "splice", Builtins::ArraySplice);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001592 InstallBuiltin(holder, "concat", Builtins::ArrayConcat);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001593
1594 return *holder;
1595}
1596
1597
lrn@chromium.org303ada72010-10-27 09:33:13 +00001598static MaybeObject* Runtime_GetGlobalReceiver(Arguments args) {
ager@chromium.org357bf652010-04-12 11:30:10 +00001599 // Returns a real global receiver, not one of builtins object.
1600 Context* global_context = Top::context()->global()->global_context();
1601 return global_context->global()->global_receiver();
1602}
1603
1604
lrn@chromium.org303ada72010-10-27 09:33:13 +00001605static MaybeObject* Runtime_MaterializeRegExpLiteral(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001606 HandleScope scope;
1607 ASSERT(args.length() == 4);
1608 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
1609 int index = Smi::cast(args[1])->value();
1610 Handle<String> pattern = args.at<String>(2);
1611 Handle<String> flags = args.at<String>(3);
1612
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001613 // Get the RegExp function from the context in the literals array.
1614 // This is the RegExp function from the context in which the
1615 // function was created. We do not use the RegExp function from the
1616 // current global context because this might be the RegExp function
1617 // from another context which we should not have access to.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001618 Handle<JSFunction> constructor =
ager@chromium.org236ad962008-09-25 09:45:57 +00001619 Handle<JSFunction>(
1620 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001621 // Compute the regular expression literal.
1622 bool has_pending_exception;
1623 Handle<Object> regexp =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001624 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
1625 &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001626 if (has_pending_exception) {
1627 ASSERT(Top::has_pending_exception());
1628 return Failure::Exception();
1629 }
1630 literals->set(index, *regexp);
1631 return *regexp;
1632}
1633
1634
lrn@chromium.org303ada72010-10-27 09:33:13 +00001635static MaybeObject* Runtime_FunctionGetName(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001636 NoHandleAllocation ha;
1637 ASSERT(args.length() == 1);
1638
1639 CONVERT_CHECKED(JSFunction, f, args[0]);
1640 return f->shared()->name();
1641}
1642
1643
lrn@chromium.org303ada72010-10-27 09:33:13 +00001644static MaybeObject* Runtime_FunctionSetName(Arguments args) {
ager@chromium.org236ad962008-09-25 09:45:57 +00001645 NoHandleAllocation ha;
1646 ASSERT(args.length() == 2);
1647
1648 CONVERT_CHECKED(JSFunction, f, args[0]);
1649 CONVERT_CHECKED(String, name, args[1]);
1650 f->shared()->set_name(name);
1651 return Heap::undefined_value();
1652}
1653
1654
lrn@chromium.org303ada72010-10-27 09:33:13 +00001655static MaybeObject* Runtime_FunctionRemovePrototype(Arguments args) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001656 NoHandleAllocation ha;
1657 ASSERT(args.length() == 1);
1658
1659 CONVERT_CHECKED(JSFunction, f, args[0]);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001660 Object* obj;
1661 { MaybeObject* maybe_obj = f->RemovePrototype();
1662 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1663 }
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001664
1665 return Heap::undefined_value();
1666}
1667
1668
lrn@chromium.org303ada72010-10-27 09:33:13 +00001669static MaybeObject* Runtime_FunctionGetScript(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001670 HandleScope scope;
1671 ASSERT(args.length() == 1);
1672
1673 CONVERT_CHECKED(JSFunction, fun, args[0]);
1674 Handle<Object> script = Handle<Object>(fun->shared()->script());
1675 if (!script->IsScript()) return Heap::undefined_value();
1676
1677 return *GetScriptWrapper(Handle<Script>::cast(script));
1678}
1679
1680
lrn@chromium.org303ada72010-10-27 09:33:13 +00001681static MaybeObject* Runtime_FunctionGetSourceCode(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001682 NoHandleAllocation ha;
1683 ASSERT(args.length() == 1);
1684
1685 CONVERT_CHECKED(JSFunction, f, args[0]);
1686 return f->shared()->GetSourceCode();
1687}
1688
1689
lrn@chromium.org303ada72010-10-27 09:33:13 +00001690static MaybeObject* Runtime_FunctionGetScriptSourcePosition(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001691 NoHandleAllocation ha;
1692 ASSERT(args.length() == 1);
1693
1694 CONVERT_CHECKED(JSFunction, fun, args[0]);
1695 int pos = fun->shared()->start_position();
1696 return Smi::FromInt(pos);
1697}
1698
1699
lrn@chromium.org303ada72010-10-27 09:33:13 +00001700static MaybeObject* Runtime_FunctionGetPositionForOffset(Arguments args) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001701 ASSERT(args.length() == 2);
1702
1703 CONVERT_CHECKED(JSFunction, fun, args[0]);
1704 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
1705
1706 Code* code = fun->code();
1707 RUNTIME_ASSERT(0 <= offset && offset < code->Size());
1708
1709 Address pc = code->address() + offset;
1710 return Smi::FromInt(fun->code()->SourcePosition(pc));
1711}
1712
1713
1714
lrn@chromium.org303ada72010-10-27 09:33:13 +00001715static MaybeObject* Runtime_FunctionSetInstanceClassName(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001716 NoHandleAllocation ha;
1717 ASSERT(args.length() == 2);
1718
1719 CONVERT_CHECKED(JSFunction, fun, args[0]);
1720 CONVERT_CHECKED(String, name, args[1]);
1721 fun->SetInstanceClassName(name);
1722 return Heap::undefined_value();
1723}
1724
1725
lrn@chromium.org303ada72010-10-27 09:33:13 +00001726static MaybeObject* Runtime_FunctionSetLength(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001727 NoHandleAllocation ha;
1728 ASSERT(args.length() == 2);
1729
1730 CONVERT_CHECKED(JSFunction, fun, args[0]);
1731 CONVERT_CHECKED(Smi, length, args[1]);
1732 fun->shared()->set_length(length->value());
1733 return length;
1734}
1735
1736
lrn@chromium.org303ada72010-10-27 09:33:13 +00001737static MaybeObject* Runtime_FunctionSetPrototype(Arguments args) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001738 NoHandleAllocation ha;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001739 ASSERT(args.length() == 2);
1740
1741 CONVERT_CHECKED(JSFunction, fun, args[0]);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001742 ASSERT(fun->should_have_prototype());
lrn@chromium.org303ada72010-10-27 09:33:13 +00001743 Object* obj;
1744 { MaybeObject* maybe_obj =
1745 Accessors::FunctionSetPrototype(fun, args[1], NULL);
1746 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1747 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001748 return args[0]; // return TOS
1749}
1750
1751
lrn@chromium.org303ada72010-10-27 09:33:13 +00001752static MaybeObject* Runtime_FunctionIsAPIFunction(Arguments args) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001753 NoHandleAllocation ha;
1754 ASSERT(args.length() == 1);
1755
1756 CONVERT_CHECKED(JSFunction, f, args[0]);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001757 return f->shared()->IsApiFunction() ? Heap::true_value()
1758 : Heap::false_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001759}
1760
lrn@chromium.org303ada72010-10-27 09:33:13 +00001761static MaybeObject* Runtime_FunctionIsBuiltin(Arguments args) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001762 NoHandleAllocation ha;
1763 ASSERT(args.length() == 1);
1764
1765 CONVERT_CHECKED(JSFunction, f, args[0]);
1766 return f->IsBuiltin() ? Heap::true_value() : Heap::false_value();
1767}
1768
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001769
lrn@chromium.org303ada72010-10-27 09:33:13 +00001770static MaybeObject* Runtime_SetCode(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001771 HandleScope scope;
1772 ASSERT(args.length() == 2);
1773
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001774 CONVERT_ARG_CHECKED(JSFunction, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001775 Handle<Object> code = args.at<Object>(1);
1776
1777 Handle<Context> context(target->context());
1778
1779 if (!code->IsNull()) {
1780 RUNTIME_ASSERT(code->IsJSFunction());
1781 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001782 Handle<SharedFunctionInfo> shared(fun->shared());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001783
1784 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001785 return Failure::Exception();
1786 }
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001787 // Set the code, scope info, formal parameter count,
1788 // and the length of the target function.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00001789 target->shared()->set_code(shared->code());
1790 target->set_code(shared->code());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001791 target->shared()->set_scope_info(shared->scope_info());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001792 target->shared()->set_length(shared->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001793 target->shared()->set_formal_parameter_count(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001794 shared->formal_parameter_count());
ager@chromium.org7c537e22008-10-16 08:43:32 +00001795 // Set the source code of the target function to undefined.
1796 // SetCode is only used for built-in constructors like String,
1797 // Array, and Object, and some web code
1798 // doesn't like seeing source code for constructors.
1799 target->shared()->set_script(Heap::undefined_value());
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001800 // Clear the optimization hints related to the compiled code as these are no
1801 // longer valid when the code is overwritten.
1802 target->shared()->ClearThisPropertyAssignmentsInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001803 context = Handle<Context>(fun->context());
1804
1805 // Make sure we get a fresh copy of the literal vector to avoid
1806 // cross context contamination.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001807 int number_of_literals = fun->NumberOfLiterals();
1808 Handle<FixedArray> literals =
1809 Factory::NewFixedArray(number_of_literals, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001810 if (number_of_literals > 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001811 // Insert the object, regexp and array functions in the literals
1812 // array prefix. These are the functions that will be used when
1813 // creating object, regexp and array literals.
ager@chromium.org236ad962008-09-25 09:45:57 +00001814 literals->set(JSFunction::kLiteralGlobalContextIndex,
1815 context->global_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001816 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001817 // It's okay to skip the write barrier here because the literals
1818 // are guaranteed to be in old space.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001819 target->set_literals(*literals, SKIP_WRITE_BARRIER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001820 }
1821
1822 target->set_context(*context);
1823 return *target;
1824}
1825
1826
lrn@chromium.org303ada72010-10-27 09:33:13 +00001827static MaybeObject* Runtime_SetExpectedNumberOfProperties(Arguments args) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001828 HandleScope scope;
1829 ASSERT(args.length() == 2);
1830 CONVERT_ARG_CHECKED(JSFunction, function, 0);
1831 CONVERT_SMI_CHECKED(num, args[1]);
1832 RUNTIME_ASSERT(num >= 0);
1833 SetExpectedNofProperties(function, num);
1834 return Heap::undefined_value();
1835}
1836
1837
lrn@chromium.org303ada72010-10-27 09:33:13 +00001838MUST_USE_RESULT static MaybeObject* CharFromCode(Object* char_code) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001839 uint32_t code;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001840 if (char_code->ToArrayIndex(&code)) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001841 if (code <= 0xffff) {
1842 return Heap::LookupSingleCharacterStringFromCode(code);
1843 }
1844 }
1845 return Heap::empty_string();
1846}
1847
1848
lrn@chromium.org303ada72010-10-27 09:33:13 +00001849static MaybeObject* Runtime_StringCharCodeAt(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001850 NoHandleAllocation ha;
1851 ASSERT(args.length() == 2);
1852
1853 CONVERT_CHECKED(String, subject, args[0]);
1854 Object* index = args[1];
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001855 RUNTIME_ASSERT(index->IsNumber());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001856
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001857 uint32_t i = 0;
1858 if (index->IsSmi()) {
1859 int value = Smi::cast(index)->value();
1860 if (value < 0) return Heap::nan_value();
1861 i = value;
1862 } else {
1863 ASSERT(index->IsHeapNumber());
1864 double value = HeapNumber::cast(index)->value();
1865 i = static_cast<uint32_t>(DoubleToInteger(value));
kasperl@chromium.org74e4e5e2010-01-25 10:15:52 +00001866 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001867
1868 // Flatten the string. If someone wants to get a char at an index
1869 // in a cons string, it is likely that more indices will be
1870 // accessed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001871 Object* flat;
1872 { MaybeObject* maybe_flat = subject->TryFlatten();
1873 if (!maybe_flat->ToObject(&flat)) return maybe_flat;
1874 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001875 subject = String::cast(flat);
1876
1877 if (i >= static_cast<uint32_t>(subject->length())) {
1878 return Heap::nan_value();
1879 }
1880
1881 return Smi::FromInt(subject->Get(i));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001882}
1883
1884
lrn@chromium.org303ada72010-10-27 09:33:13 +00001885static MaybeObject* Runtime_CharFromCode(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001886 NoHandleAllocation ha;
1887 ASSERT(args.length() == 1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001888 return CharFromCode(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001889}
1890
lrn@chromium.org25156de2010-04-06 13:10:27 +00001891
1892class FixedArrayBuilder {
1893 public:
1894 explicit FixedArrayBuilder(int initial_capacity)
1895 : array_(Factory::NewFixedArrayWithHoles(initial_capacity)),
1896 length_(0) {
1897 // Require a non-zero initial size. Ensures that doubling the size to
1898 // extend the array will work.
1899 ASSERT(initial_capacity > 0);
1900 }
1901
1902 explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
1903 : array_(backing_store),
1904 length_(0) {
1905 // Require a non-zero initial size. Ensures that doubling the size to
1906 // extend the array will work.
1907 ASSERT(backing_store->length() > 0);
1908 }
1909
1910 bool HasCapacity(int elements) {
1911 int length = array_->length();
1912 int required_length = length_ + elements;
1913 return (length >= required_length);
1914 }
1915
1916 void EnsureCapacity(int elements) {
1917 int length = array_->length();
1918 int required_length = length_ + elements;
1919 if (length < required_length) {
1920 int new_length = length;
1921 do {
1922 new_length *= 2;
1923 } while (new_length < required_length);
1924 Handle<FixedArray> extended_array =
1925 Factory::NewFixedArrayWithHoles(new_length);
1926 array_->CopyTo(0, *extended_array, 0, length_);
1927 array_ = extended_array;
1928 }
1929 }
1930
1931 void Add(Object* value) {
1932 ASSERT(length_ < capacity());
1933 array_->set(length_, value);
1934 length_++;
1935 }
1936
1937 void Add(Smi* value) {
1938 ASSERT(length_ < capacity());
1939 array_->set(length_, value);
1940 length_++;
1941 }
1942
1943 Handle<FixedArray> array() {
1944 return array_;
1945 }
1946
1947 int length() {
1948 return length_;
1949 }
1950
1951 int capacity() {
1952 return array_->length();
1953 }
1954
1955 Handle<JSArray> ToJSArray() {
1956 Handle<JSArray> result_array = Factory::NewJSArrayWithElements(array_);
1957 result_array->set_length(Smi::FromInt(length_));
1958 return result_array;
1959 }
1960
1961 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
1962 target_array->set_elements(*array_);
1963 target_array->set_length(Smi::FromInt(length_));
1964 return target_array;
1965 }
1966
1967 private:
1968 Handle<FixedArray> array_;
1969 int length_;
1970};
1971
1972
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001973// Forward declarations.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001974const int kStringBuilderConcatHelperLengthBits = 11;
1975const int kStringBuilderConcatHelperPositionBits = 19;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001976
1977template <typename schar>
1978static inline void StringBuilderConcatHelper(String*,
1979 schar*,
1980 FixedArray*,
1981 int);
1982
lrn@chromium.org25156de2010-04-06 13:10:27 +00001983typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
1984 StringBuilderSubstringLength;
1985typedef BitField<int,
1986 kStringBuilderConcatHelperLengthBits,
1987 kStringBuilderConcatHelperPositionBits>
1988 StringBuilderSubstringPosition;
1989
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001990
1991class ReplacementStringBuilder {
1992 public:
1993 ReplacementStringBuilder(Handle<String> subject, int estimated_part_count)
lrn@chromium.org25156de2010-04-06 13:10:27 +00001994 : array_builder_(estimated_part_count),
1995 subject_(subject),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001996 character_count_(0),
ager@chromium.org5ec48922009-05-05 07:25:34 +00001997 is_ascii_(subject->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001998 // Require a non-zero initial size. Ensures that doubling the size to
1999 // extend the array will work.
2000 ASSERT(estimated_part_count > 0);
2001 }
2002
lrn@chromium.org25156de2010-04-06 13:10:27 +00002003 static inline void AddSubjectSlice(FixedArrayBuilder* builder,
2004 int from,
2005 int to) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002006 ASSERT(from >= 0);
2007 int length = to - from;
2008 ASSERT(length > 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002009 if (StringBuilderSubstringLength::is_valid(length) &&
2010 StringBuilderSubstringPosition::is_valid(from)) {
2011 int encoded_slice = StringBuilderSubstringLength::encode(length) |
2012 StringBuilderSubstringPosition::encode(from);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002013 builder->Add(Smi::FromInt(encoded_slice));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002014 } else {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002015 // Otherwise encode as two smis.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002016 builder->Add(Smi::FromInt(-length));
2017 builder->Add(Smi::FromInt(from));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002018 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00002019 }
2020
2021
2022 void EnsureCapacity(int elements) {
2023 array_builder_.EnsureCapacity(elements);
2024 }
2025
2026
2027 void AddSubjectSlice(int from, int to) {
2028 AddSubjectSlice(&array_builder_, from, to);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002029 IncrementCharacterCount(to - from);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002030 }
2031
2032
2033 void AddString(Handle<String> string) {
2034 int length = string->length();
2035 ASSERT(length > 0);
2036 AddElement(*string);
ager@chromium.org5ec48922009-05-05 07:25:34 +00002037 if (!string->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002038 is_ascii_ = false;
2039 }
2040 IncrementCharacterCount(length);
2041 }
2042
2043
2044 Handle<String> ToString() {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002045 if (array_builder_.length() == 0) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002046 return Factory::empty_string();
2047 }
2048
2049 Handle<String> joined_string;
2050 if (is_ascii_) {
2051 joined_string = NewRawAsciiString(character_count_);
2052 AssertNoAllocation no_alloc;
2053 SeqAsciiString* seq = SeqAsciiString::cast(*joined_string);
2054 char* char_buffer = seq->GetChars();
2055 StringBuilderConcatHelper(*subject_,
2056 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002057 *array_builder_.array(),
2058 array_builder_.length());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002059 } else {
2060 // Non-ASCII.
2061 joined_string = NewRawTwoByteString(character_count_);
2062 AssertNoAllocation no_alloc;
2063 SeqTwoByteString* seq = SeqTwoByteString::cast(*joined_string);
2064 uc16* char_buffer = seq->GetChars();
2065 StringBuilderConcatHelper(*subject_,
2066 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002067 *array_builder_.array(),
2068 array_builder_.length());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002069 }
2070 return joined_string;
2071 }
2072
2073
2074 void IncrementCharacterCount(int by) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002075 if (character_count_ > String::kMaxLength - by) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002076 V8::FatalProcessOutOfMemory("String.replace result too large.");
2077 }
2078 character_count_ += by;
2079 }
2080
lrn@chromium.org25156de2010-04-06 13:10:27 +00002081 Handle<JSArray> GetParts() {
2082 Handle<JSArray> result =
2083 Factory::NewJSArrayWithElements(array_builder_.array());
2084 result->set_length(Smi::FromInt(array_builder_.length()));
2085 return result;
2086 }
kmillikin@chromium.orgd9825192010-03-30 08:36:16 +00002087
lrn@chromium.org25156de2010-04-06 13:10:27 +00002088 private:
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002089 Handle<String> NewRawAsciiString(int size) {
2090 CALL_HEAP_FUNCTION(Heap::AllocateRawAsciiString(size), String);
2091 }
2092
2093
2094 Handle<String> NewRawTwoByteString(int size) {
2095 CALL_HEAP_FUNCTION(Heap::AllocateRawTwoByteString(size), String);
2096 }
2097
2098
2099 void AddElement(Object* element) {
2100 ASSERT(element->IsSmi() || element->IsString());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002101 ASSERT(array_builder_.capacity() > array_builder_.length());
2102 array_builder_.Add(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002103 }
2104
lrn@chromium.org25156de2010-04-06 13:10:27 +00002105 FixedArrayBuilder array_builder_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002106 Handle<String> subject_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002107 int character_count_;
2108 bool is_ascii_;
2109};
2110
2111
2112class CompiledReplacement {
2113 public:
2114 CompiledReplacement()
2115 : parts_(1), replacement_substrings_(0) {}
2116
2117 void Compile(Handle<String> replacement,
2118 int capture_count,
2119 int subject_length);
2120
2121 void Apply(ReplacementStringBuilder* builder,
2122 int match_from,
2123 int match_to,
2124 Handle<JSArray> last_match_info);
2125
2126 // Number of distinct parts of the replacement pattern.
2127 int parts() {
2128 return parts_.length();
2129 }
2130 private:
2131 enum PartType {
2132 SUBJECT_PREFIX = 1,
2133 SUBJECT_SUFFIX,
2134 SUBJECT_CAPTURE,
2135 REPLACEMENT_SUBSTRING,
2136 REPLACEMENT_STRING,
2137
2138 NUMBER_OF_PART_TYPES
2139 };
2140
2141 struct ReplacementPart {
2142 static inline ReplacementPart SubjectMatch() {
2143 return ReplacementPart(SUBJECT_CAPTURE, 0);
2144 }
2145 static inline ReplacementPart SubjectCapture(int capture_index) {
2146 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
2147 }
2148 static inline ReplacementPart SubjectPrefix() {
2149 return ReplacementPart(SUBJECT_PREFIX, 0);
2150 }
2151 static inline ReplacementPart SubjectSuffix(int subject_length) {
2152 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
2153 }
2154 static inline ReplacementPart ReplacementString() {
2155 return ReplacementPart(REPLACEMENT_STRING, 0);
2156 }
2157 static inline ReplacementPart ReplacementSubString(int from, int to) {
2158 ASSERT(from >= 0);
2159 ASSERT(to > from);
2160 return ReplacementPart(-from, to);
2161 }
2162
2163 // If tag <= 0 then it is the negation of a start index of a substring of
2164 // the replacement pattern, otherwise it's a value from PartType.
2165 ReplacementPart(int tag, int data)
2166 : tag(tag), data(data) {
2167 // Must be non-positive or a PartType value.
2168 ASSERT(tag < NUMBER_OF_PART_TYPES);
2169 }
2170 // Either a value of PartType or a non-positive number that is
2171 // the negation of an index into the replacement string.
2172 int tag;
2173 // The data value's interpretation depends on the value of tag:
2174 // tag == SUBJECT_PREFIX ||
2175 // tag == SUBJECT_SUFFIX: data is unused.
2176 // tag == SUBJECT_CAPTURE: data is the number of the capture.
2177 // tag == REPLACEMENT_SUBSTRING ||
2178 // tag == REPLACEMENT_STRING: data is index into array of substrings
2179 // of the replacement string.
2180 // tag <= 0: Temporary representation of the substring of the replacement
2181 // string ranging over -tag .. data.
2182 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
2183 // substring objects.
2184 int data;
2185 };
2186
2187 template<typename Char>
2188 static void ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
2189 Vector<Char> characters,
2190 int capture_count,
2191 int subject_length) {
2192 int length = characters.length();
2193 int last = 0;
2194 for (int i = 0; i < length; i++) {
2195 Char c = characters[i];
2196 if (c == '$') {
2197 int next_index = i + 1;
2198 if (next_index == length) { // No next character!
2199 break;
2200 }
2201 Char c2 = characters[next_index];
2202 switch (c2) {
2203 case '$':
2204 if (i > last) {
2205 // There is a substring before. Include the first "$".
2206 parts->Add(ReplacementPart::ReplacementSubString(last, next_index));
2207 last = next_index + 1; // Continue after the second "$".
2208 } else {
2209 // Let the next substring start with the second "$".
2210 last = next_index;
2211 }
2212 i = next_index;
2213 break;
2214 case '`':
2215 if (i > last) {
2216 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2217 }
2218 parts->Add(ReplacementPart::SubjectPrefix());
2219 i = next_index;
2220 last = i + 1;
2221 break;
2222 case '\'':
2223 if (i > last) {
2224 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2225 }
2226 parts->Add(ReplacementPart::SubjectSuffix(subject_length));
2227 i = next_index;
2228 last = i + 1;
2229 break;
2230 case '&':
2231 if (i > last) {
2232 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2233 }
2234 parts->Add(ReplacementPart::SubjectMatch());
2235 i = next_index;
2236 last = i + 1;
2237 break;
2238 case '0':
2239 case '1':
2240 case '2':
2241 case '3':
2242 case '4':
2243 case '5':
2244 case '6':
2245 case '7':
2246 case '8':
2247 case '9': {
2248 int capture_ref = c2 - '0';
2249 if (capture_ref > capture_count) {
2250 i = next_index;
2251 continue;
2252 }
2253 int second_digit_index = next_index + 1;
2254 if (second_digit_index < length) {
2255 // Peek ahead to see if we have two digits.
2256 Char c3 = characters[second_digit_index];
2257 if ('0' <= c3 && c3 <= '9') { // Double digits.
2258 int double_digit_ref = capture_ref * 10 + c3 - '0';
2259 if (double_digit_ref <= capture_count) {
2260 next_index = second_digit_index;
2261 capture_ref = double_digit_ref;
2262 }
2263 }
2264 }
2265 if (capture_ref > 0) {
2266 if (i > last) {
2267 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2268 }
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002269 ASSERT(capture_ref <= capture_count);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002270 parts->Add(ReplacementPart::SubjectCapture(capture_ref));
2271 last = next_index + 1;
2272 }
2273 i = next_index;
2274 break;
2275 }
2276 default:
2277 i = next_index;
2278 break;
2279 }
2280 }
2281 }
2282 if (length > last) {
2283 if (last == 0) {
2284 parts->Add(ReplacementPart::ReplacementString());
2285 } else {
2286 parts->Add(ReplacementPart::ReplacementSubString(last, length));
2287 }
2288 }
2289 }
2290
2291 ZoneList<ReplacementPart> parts_;
2292 ZoneList<Handle<String> > replacement_substrings_;
2293};
2294
2295
2296void CompiledReplacement::Compile(Handle<String> replacement,
2297 int capture_count,
2298 int subject_length) {
2299 ASSERT(replacement->IsFlat());
ager@chromium.org5ec48922009-05-05 07:25:34 +00002300 if (replacement->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002301 AssertNoAllocation no_alloc;
2302 ParseReplacementPattern(&parts_,
2303 replacement->ToAsciiVector(),
2304 capture_count,
2305 subject_length);
2306 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00002307 ASSERT(replacement->IsTwoByteRepresentation());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002308 AssertNoAllocation no_alloc;
2309
2310 ParseReplacementPattern(&parts_,
2311 replacement->ToUC16Vector(),
2312 capture_count,
2313 subject_length);
2314 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002315 // Find substrings of replacement string and create them as String objects.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002316 int substring_index = 0;
2317 for (int i = 0, n = parts_.length(); i < n; i++) {
2318 int tag = parts_[i].tag;
2319 if (tag <= 0) { // A replacement string slice.
2320 int from = -tag;
2321 int to = parts_[i].data;
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002322 replacement_substrings_.Add(Factory::NewSubString(replacement, from, to));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002323 parts_[i].tag = REPLACEMENT_SUBSTRING;
2324 parts_[i].data = substring_index;
2325 substring_index++;
2326 } else if (tag == REPLACEMENT_STRING) {
2327 replacement_substrings_.Add(replacement);
2328 parts_[i].data = substring_index;
2329 substring_index++;
2330 }
2331 }
2332}
2333
2334
2335void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
2336 int match_from,
2337 int match_to,
2338 Handle<JSArray> last_match_info) {
2339 for (int i = 0, n = parts_.length(); i < n; i++) {
2340 ReplacementPart part = parts_[i];
2341 switch (part.tag) {
2342 case SUBJECT_PREFIX:
2343 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
2344 break;
2345 case SUBJECT_SUFFIX: {
2346 int subject_length = part.data;
2347 if (match_to < subject_length) {
2348 builder->AddSubjectSlice(match_to, subject_length);
2349 }
2350 break;
2351 }
2352 case SUBJECT_CAPTURE: {
2353 int capture = part.data;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002354 FixedArray* match_info = FixedArray::cast(last_match_info->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002355 int from = RegExpImpl::GetCapture(match_info, capture * 2);
2356 int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1);
2357 if (from >= 0 && to > from) {
2358 builder->AddSubjectSlice(from, to);
2359 }
2360 break;
2361 }
2362 case REPLACEMENT_SUBSTRING:
2363 case REPLACEMENT_STRING:
2364 builder->AddString(replacement_substrings_[part.data]);
2365 break;
2366 default:
2367 UNREACHABLE();
2368 }
2369 }
2370}
2371
2372
2373
lrn@chromium.org303ada72010-10-27 09:33:13 +00002374MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
2375 String* subject,
2376 JSRegExp* regexp,
2377 String* replacement,
2378 JSArray* last_match_info) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002379 ASSERT(subject->IsFlat());
2380 ASSERT(replacement->IsFlat());
2381
2382 HandleScope handles;
2383
2384 int length = subject->length();
2385 Handle<String> subject_handle(subject);
2386 Handle<JSRegExp> regexp_handle(regexp);
2387 Handle<String> replacement_handle(replacement);
2388 Handle<JSArray> last_match_info_handle(last_match_info);
2389 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2390 subject_handle,
2391 0,
2392 last_match_info_handle);
2393 if (match.is_null()) {
2394 return Failure::Exception();
2395 }
2396 if (match->IsNull()) {
2397 return *subject_handle;
2398 }
2399
2400 int capture_count = regexp_handle->CaptureCount();
2401
2402 // CompiledReplacement uses zone allocation.
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00002403 CompilationZoneScope zone(DELETE_ON_EXIT);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002404 CompiledReplacement compiled_replacement;
2405 compiled_replacement.Compile(replacement_handle,
2406 capture_count,
2407 length);
2408
2409 bool is_global = regexp_handle->GetFlags().is_global();
2410
2411 // Guessing the number of parts that the final result string is built
2412 // from. Global regexps can match any number of times, so we guess
2413 // conservatively.
2414 int expected_parts =
2415 (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1;
2416 ReplacementStringBuilder builder(subject_handle, expected_parts);
2417
2418 // Index of end of last match.
2419 int prev = 0;
2420
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002421 // Number of parts added by compiled replacement plus preceeding
2422 // string and possibly suffix after last match. It is possible for
2423 // all components to use two elements when encoded as two smis.
2424 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002425 bool matched = true;
2426 do {
2427 ASSERT(last_match_info_handle->HasFastElements());
2428 // Increase the capacity of the builder before entering local handle-scope,
2429 // so its internal buffer can safely allocate a new handle if it grows.
2430 builder.EnsureCapacity(parts_added_per_loop);
2431
2432 HandleScope loop_scope;
2433 int start, end;
2434 {
2435 AssertNoAllocation match_info_array_is_not_in_a_handle;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002436 FixedArray* match_info_array =
2437 FixedArray::cast(last_match_info_handle->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002438
2439 ASSERT_EQ(capture_count * 2 + 2,
2440 RegExpImpl::GetLastCaptureCount(match_info_array));
2441 start = RegExpImpl::GetCapture(match_info_array, 0);
2442 end = RegExpImpl::GetCapture(match_info_array, 1);
2443 }
2444
2445 if (prev < start) {
2446 builder.AddSubjectSlice(prev, start);
2447 }
2448 compiled_replacement.Apply(&builder,
2449 start,
2450 end,
2451 last_match_info_handle);
2452 prev = end;
2453
2454 // Only continue checking for global regexps.
2455 if (!is_global) break;
2456
2457 // Continue from where the match ended, unless it was an empty match.
2458 int next = end;
2459 if (start == end) {
2460 next = end + 1;
2461 if (next > length) break;
2462 }
2463
2464 match = RegExpImpl::Exec(regexp_handle,
2465 subject_handle,
2466 next,
2467 last_match_info_handle);
2468 if (match.is_null()) {
2469 return Failure::Exception();
2470 }
2471 matched = !match->IsNull();
2472 } while (matched);
2473
2474 if (prev < length) {
2475 builder.AddSubjectSlice(prev, length);
2476 }
2477
2478 return *(builder.ToString());
2479}
2480
2481
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002482template <typename ResultSeqString>
lrn@chromium.org303ada72010-10-27 09:33:13 +00002483MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
2484 String* subject,
2485 JSRegExp* regexp,
2486 JSArray* last_match_info) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002487 ASSERT(subject->IsFlat());
2488
2489 HandleScope handles;
2490
2491 Handle<String> subject_handle(subject);
2492 Handle<JSRegExp> regexp_handle(regexp);
2493 Handle<JSArray> last_match_info_handle(last_match_info);
2494 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2495 subject_handle,
2496 0,
2497 last_match_info_handle);
2498 if (match.is_null()) return Failure::Exception();
2499 if (match->IsNull()) return *subject_handle;
2500
2501 ASSERT(last_match_info_handle->HasFastElements());
2502
2503 HandleScope loop_scope;
2504 int start, end;
2505 {
2506 AssertNoAllocation match_info_array_is_not_in_a_handle;
2507 FixedArray* match_info_array =
2508 FixedArray::cast(last_match_info_handle->elements());
2509
2510 start = RegExpImpl::GetCapture(match_info_array, 0);
2511 end = RegExpImpl::GetCapture(match_info_array, 1);
2512 }
2513
2514 int length = subject->length();
2515 int new_length = length - (end - start);
2516 if (new_length == 0) {
2517 return Heap::empty_string();
2518 }
2519 Handle<ResultSeqString> answer;
2520 if (ResultSeqString::kHasAsciiEncoding) {
2521 answer =
2522 Handle<ResultSeqString>::cast(Factory::NewRawAsciiString(new_length));
2523 } else {
2524 answer =
2525 Handle<ResultSeqString>::cast(Factory::NewRawTwoByteString(new_length));
2526 }
2527
2528 // If the regexp isn't global, only match once.
2529 if (!regexp_handle->GetFlags().is_global()) {
2530 if (start > 0) {
2531 String::WriteToFlat(*subject_handle,
2532 answer->GetChars(),
2533 0,
2534 start);
2535 }
2536 if (end < length) {
2537 String::WriteToFlat(*subject_handle,
2538 answer->GetChars() + start,
2539 end,
2540 length);
2541 }
2542 return *answer;
2543 }
2544
2545 int prev = 0; // Index of end of last match.
2546 int next = 0; // Start of next search (prev unless last match was empty).
2547 int position = 0;
2548
2549 do {
2550 if (prev < start) {
2551 // Add substring subject[prev;start] to answer string.
2552 String::WriteToFlat(*subject_handle,
2553 answer->GetChars() + position,
2554 prev,
2555 start);
2556 position += start - prev;
2557 }
2558 prev = end;
2559 next = end;
2560 // Continue from where the match ended, unless it was an empty match.
2561 if (start == end) {
2562 next++;
2563 if (next > length) break;
2564 }
2565 match = RegExpImpl::Exec(regexp_handle,
2566 subject_handle,
2567 next,
2568 last_match_info_handle);
2569 if (match.is_null()) return Failure::Exception();
2570 if (match->IsNull()) break;
2571
2572 ASSERT(last_match_info_handle->HasFastElements());
2573 HandleScope loop_scope;
2574 {
2575 AssertNoAllocation match_info_array_is_not_in_a_handle;
2576 FixedArray* match_info_array =
2577 FixedArray::cast(last_match_info_handle->elements());
2578 start = RegExpImpl::GetCapture(match_info_array, 0);
2579 end = RegExpImpl::GetCapture(match_info_array, 1);
2580 }
2581 } while (true);
2582
2583 if (prev < length) {
2584 // Add substring subject[prev;length] to answer string.
2585 String::WriteToFlat(*subject_handle,
2586 answer->GetChars() + position,
2587 prev,
2588 length);
2589 position += length - prev;
2590 }
2591
2592 if (position == 0) {
2593 return Heap::empty_string();
2594 }
2595
2596 // Shorten string and fill
2597 int string_size = ResultSeqString::SizeFor(position);
2598 int allocated_string_size = ResultSeqString::SizeFor(new_length);
2599 int delta = allocated_string_size - string_size;
2600
2601 answer->set_length(position);
2602 if (delta == 0) return *answer;
2603
2604 Address end_of_string = answer->address() + string_size;
2605 Heap::CreateFillerObjectAt(end_of_string, delta);
2606
2607 return *answer;
2608}
2609
2610
lrn@chromium.org303ada72010-10-27 09:33:13 +00002611static MaybeObject* Runtime_StringReplaceRegExpWithString(Arguments args) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002612 ASSERT(args.length() == 4);
2613
2614 CONVERT_CHECKED(String, subject, args[0]);
2615 if (!subject->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002616 Object* flat_subject;
2617 { MaybeObject* maybe_flat_subject = subject->TryFlatten();
2618 if (!maybe_flat_subject->ToObject(&flat_subject)) {
2619 return maybe_flat_subject;
2620 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002621 }
2622 subject = String::cast(flat_subject);
2623 }
2624
2625 CONVERT_CHECKED(String, replacement, args[2]);
2626 if (!replacement->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002627 Object* flat_replacement;
2628 { MaybeObject* maybe_flat_replacement = replacement->TryFlatten();
2629 if (!maybe_flat_replacement->ToObject(&flat_replacement)) {
2630 return maybe_flat_replacement;
2631 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002632 }
2633 replacement = String::cast(flat_replacement);
2634 }
2635
2636 CONVERT_CHECKED(JSRegExp, regexp, args[1]);
2637 CONVERT_CHECKED(JSArray, last_match_info, args[3]);
2638
2639 ASSERT(last_match_info->HasFastElements());
2640
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002641 if (replacement->length() == 0) {
2642 if (subject->HasOnlyAsciiChars()) {
2643 return StringReplaceRegExpWithEmptyString<SeqAsciiString>(
2644 subject, regexp, last_match_info);
2645 } else {
2646 return StringReplaceRegExpWithEmptyString<SeqTwoByteString>(
2647 subject, regexp, last_match_info);
2648 }
2649 }
2650
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002651 return StringReplaceRegExpWithString(subject,
2652 regexp,
2653 replacement,
2654 last_match_info);
2655}
2656
2657
ager@chromium.org7c537e22008-10-16 08:43:32 +00002658// Perform string match of pattern on subject, starting at start index.
2659// Caller must ensure that 0 <= start_index <= sub->length(),
2660// and should check that pat->length() + start_index <= sub->length()
2661int Runtime::StringMatch(Handle<String> sub,
2662 Handle<String> pat,
2663 int start_index) {
2664 ASSERT(0 <= start_index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002665 ASSERT(start_index <= sub->length());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002666
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00002667 int pattern_length = pat->length();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002668 if (pattern_length == 0) return start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002669
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002670 int subject_length = sub->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00002671 if (start_index + pattern_length > subject_length) return -1;
2672
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002673 if (!sub->IsFlat()) FlattenString(sub);
2674 if (!pat->IsFlat()) FlattenString(pat);
ager@chromium.org236ad962008-09-25 09:45:57 +00002675
ager@chromium.org7c537e22008-10-16 08:43:32 +00002676 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002677 // Extract flattened substrings of cons strings before determining asciiness.
2678 String* seq_sub = *sub;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002679 if (seq_sub->IsConsString()) seq_sub = ConsString::cast(seq_sub)->first();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002680 String* seq_pat = *pat;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002681 if (seq_pat->IsConsString()) seq_pat = ConsString::cast(seq_pat)->first();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002682
ager@chromium.org7c537e22008-10-16 08:43:32 +00002683 // dispatch on type of strings
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002684 if (seq_pat->IsAsciiRepresentation()) {
2685 Vector<const char> pat_vector = seq_pat->ToAsciiVector();
2686 if (seq_sub->IsAsciiRepresentation()) {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002687 return SearchString(seq_sub->ToAsciiVector(), pat_vector, start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00002688 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002689 return SearchString(seq_sub->ToUC16Vector(), pat_vector, start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00002690 }
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002691 Vector<const uc16> pat_vector = seq_pat->ToUC16Vector();
2692 if (seq_sub->IsAsciiRepresentation()) {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002693 return SearchString(seq_sub->ToAsciiVector(), pat_vector, start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002694 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002695 return SearchString(seq_sub->ToUC16Vector(), pat_vector, start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002696}
2697
2698
lrn@chromium.org303ada72010-10-27 09:33:13 +00002699static MaybeObject* Runtime_StringIndexOf(Arguments args) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00002700 HandleScope scope; // create a new handle scope
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002701 ASSERT(args.length() == 3);
2702
ager@chromium.org7c537e22008-10-16 08:43:32 +00002703 CONVERT_ARG_CHECKED(String, sub, 0);
2704 CONVERT_ARG_CHECKED(String, pat, 1);
2705
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002706 Object* index = args[2];
2707 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002708 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002709
ager@chromium.org870a0b62008-11-04 11:43:05 +00002710 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
ager@chromium.org7c537e22008-10-16 08:43:32 +00002711 int position = Runtime::StringMatch(sub, pat, start_index);
2712 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002713}
2714
2715
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002716template <typename schar, typename pchar>
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002717static int StringMatchBackwards(Vector<const schar> subject,
2718 Vector<const pchar> pattern,
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002719 int idx) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002720 int pattern_length = pattern.length();
2721 ASSERT(pattern_length >= 1);
2722 ASSERT(idx + pattern_length <= subject.length());
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002723
2724 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002725 for (int i = 0; i < pattern_length; i++) {
2726 uc16 c = pattern[i];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002727 if (c > String::kMaxAsciiCharCode) {
2728 return -1;
2729 }
2730 }
2731 }
2732
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002733 pchar pattern_first_char = pattern[0];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002734 for (int i = idx; i >= 0; i--) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002735 if (subject[i] != pattern_first_char) continue;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002736 int j = 1;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002737 while (j < pattern_length) {
2738 if (pattern[j] != subject[i+j]) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002739 break;
2740 }
2741 j++;
2742 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002743 if (j == pattern_length) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002744 return i;
2745 }
2746 }
2747 return -1;
2748}
2749
lrn@chromium.org303ada72010-10-27 09:33:13 +00002750static MaybeObject* Runtime_StringLastIndexOf(Arguments args) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002751 HandleScope scope; // create a new handle scope
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002752 ASSERT(args.length() == 3);
2753
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002754 CONVERT_ARG_CHECKED(String, sub, 0);
2755 CONVERT_ARG_CHECKED(String, pat, 1);
2756
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002757 Object* index = args[2];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002758 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002759 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002760
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002761 uint32_t pat_length = pat->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002762 uint32_t sub_length = sub->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002763
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002764 if (start_index + pat_length > sub_length) {
2765 start_index = sub_length - pat_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +00002766 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002767
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002768 if (pat_length == 0) {
2769 return Smi::FromInt(start_index);
2770 }
2771
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002772 if (!sub->IsFlat()) FlattenString(sub);
2773 if (!pat->IsFlat()) FlattenString(pat);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002774
2775 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
2776
2777 int position = -1;
2778
2779 if (pat->IsAsciiRepresentation()) {
2780 Vector<const char> pat_vector = pat->ToAsciiVector();
2781 if (sub->IsAsciiRepresentation()) {
2782 position = StringMatchBackwards(sub->ToAsciiVector(),
2783 pat_vector,
2784 start_index);
2785 } else {
2786 position = StringMatchBackwards(sub->ToUC16Vector(),
2787 pat_vector,
2788 start_index);
2789 }
2790 } else {
2791 Vector<const uc16> pat_vector = pat->ToUC16Vector();
2792 if (sub->IsAsciiRepresentation()) {
2793 position = StringMatchBackwards(sub->ToAsciiVector(),
2794 pat_vector,
2795 start_index);
2796 } else {
2797 position = StringMatchBackwards(sub->ToUC16Vector(),
2798 pat_vector,
2799 start_index);
2800 }
2801 }
2802
2803 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002804}
2805
2806
lrn@chromium.org303ada72010-10-27 09:33:13 +00002807static MaybeObject* Runtime_StringLocaleCompare(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002808 NoHandleAllocation ha;
2809 ASSERT(args.length() == 2);
2810
2811 CONVERT_CHECKED(String, str1, args[0]);
2812 CONVERT_CHECKED(String, str2, args[1]);
2813
2814 if (str1 == str2) return Smi::FromInt(0); // Equal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002815 int str1_length = str1->length();
2816 int str2_length = str2->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002817
2818 // Decide trivial cases without flattening.
2819 if (str1_length == 0) {
2820 if (str2_length == 0) return Smi::FromInt(0); // Equal.
2821 return Smi::FromInt(-str2_length);
2822 } else {
2823 if (str2_length == 0) return Smi::FromInt(str1_length);
2824 }
2825
2826 int end = str1_length < str2_length ? str1_length : str2_length;
2827
2828 // No need to flatten if we are going to find the answer on the first
2829 // character. At this point we know there is at least one character
2830 // in each string, due to the trivial case handling above.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002831 int d = str1->Get(0) - str2->Get(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002832 if (d != 0) return Smi::FromInt(d);
2833
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002834 str1->TryFlatten();
2835 str2->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002836
2837 static StringInputBuffer buf1;
2838 static StringInputBuffer buf2;
2839
2840 buf1.Reset(str1);
2841 buf2.Reset(str2);
2842
2843 for (int i = 0; i < end; i++) {
2844 uint16_t char1 = buf1.GetNext();
2845 uint16_t char2 = buf2.GetNext();
2846 if (char1 != char2) return Smi::FromInt(char1 - char2);
2847 }
2848
2849 return Smi::FromInt(str1_length - str2_length);
2850}
2851
2852
lrn@chromium.org303ada72010-10-27 09:33:13 +00002853static MaybeObject* Runtime_SubString(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002854 NoHandleAllocation ha;
2855 ASSERT(args.length() == 3);
2856
2857 CONVERT_CHECKED(String, value, args[0]);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002858 Object* from = args[1];
2859 Object* to = args[2];
2860 int start, end;
2861 // We have a fast integer-only case here to avoid a conversion to double in
2862 // the common case where from and to are Smis.
2863 if (from->IsSmi() && to->IsSmi()) {
2864 start = Smi::cast(from)->value();
2865 end = Smi::cast(to)->value();
2866 } else {
2867 CONVERT_DOUBLE_CHECKED(from_number, from);
2868 CONVERT_DOUBLE_CHECKED(to_number, to);
2869 start = FastD2I(from_number);
2870 end = FastD2I(to_number);
2871 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002872 RUNTIME_ASSERT(end >= start);
2873 RUNTIME_ASSERT(start >= 0);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00002874 RUNTIME_ASSERT(end <= value->length());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002875 Counters::sub_string_runtime.Increment();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002876 return value->SubString(start, end);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002877}
2878
2879
lrn@chromium.org303ada72010-10-27 09:33:13 +00002880static MaybeObject* Runtime_StringMatch(Arguments args) {
ager@chromium.org41826e72009-03-30 13:30:57 +00002881 ASSERT_EQ(3, args.length());
2882
2883 CONVERT_ARG_CHECKED(String, subject, 0);
2884 CONVERT_ARG_CHECKED(JSRegExp, regexp, 1);
2885 CONVERT_ARG_CHECKED(JSArray, regexp_info, 2);
2886 HandleScope handles;
2887
2888 Handle<Object> match = RegExpImpl::Exec(regexp, subject, 0, regexp_info);
2889
2890 if (match.is_null()) {
2891 return Failure::Exception();
2892 }
2893 if (match->IsNull()) {
2894 return Heap::null_value();
2895 }
2896 int length = subject->length();
2897
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00002898 CompilationZoneScope zone_space(DELETE_ON_EXIT);
ager@chromium.org41826e72009-03-30 13:30:57 +00002899 ZoneList<int> offsets(8);
2900 do {
2901 int start;
2902 int end;
2903 {
2904 AssertNoAllocation no_alloc;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002905 FixedArray* elements = FixedArray::cast(regexp_info->elements());
ager@chromium.org41826e72009-03-30 13:30:57 +00002906 start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value();
2907 end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value();
2908 }
2909 offsets.Add(start);
2910 offsets.Add(end);
2911 int index = start < end ? end : end + 1;
2912 if (index > length) break;
2913 match = RegExpImpl::Exec(regexp, subject, index, regexp_info);
2914 if (match.is_null()) {
2915 return Failure::Exception();
2916 }
2917 } while (!match->IsNull());
2918 int matches = offsets.length() / 2;
2919 Handle<FixedArray> elements = Factory::NewFixedArray(matches);
2920 for (int i = 0; i < matches ; i++) {
2921 int from = offsets.at(i * 2);
2922 int to = offsets.at(i * 2 + 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002923 Handle<String> match = Factory::NewSubString(subject, from, to);
2924 elements->set(i, *match);
ager@chromium.org41826e72009-03-30 13:30:57 +00002925 }
2926 Handle<JSArray> result = Factory::NewJSArrayWithElements(elements);
2927 result->set_length(Smi::FromInt(matches));
2928 return *result;
2929}
2930
2931
lrn@chromium.org25156de2010-04-06 13:10:27 +00002932// Two smis before and after the match, for very long strings.
2933const int kMaxBuilderEntriesPerRegExpMatch = 5;
2934
2935
2936static void SetLastMatchInfoNoCaptures(Handle<String> subject,
2937 Handle<JSArray> last_match_info,
2938 int match_start,
2939 int match_end) {
2940 // Fill last_match_info with a single capture.
2941 last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead);
2942 AssertNoAllocation no_gc;
2943 FixedArray* elements = FixedArray::cast(last_match_info->elements());
2944 RegExpImpl::SetLastCaptureCount(elements, 2);
2945 RegExpImpl::SetLastInput(elements, *subject);
2946 RegExpImpl::SetLastSubject(elements, *subject);
2947 RegExpImpl::SetCapture(elements, 0, match_start);
2948 RegExpImpl::SetCapture(elements, 1, match_end);
2949}
2950
2951
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002952template <typename SubjectChar, typename PatternChar>
2953static bool SearchStringMultiple(Vector<const SubjectChar> subject,
2954 Vector<const PatternChar> pattern,
2955 String* pattern_string,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002956 FixedArrayBuilder* builder,
2957 int* match_pos) {
2958 int pos = *match_pos;
2959 int subject_length = subject.length();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002960 int pattern_length = pattern.length();
lrn@chromium.org25156de2010-04-06 13:10:27 +00002961 int max_search_start = subject_length - pattern_length;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002962 StringSearch<PatternChar, SubjectChar> search(pattern);
2963 while (pos <= max_search_start) {
2964 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
2965 *match_pos = pos;
2966 return false;
2967 }
2968 // Position of end of previous match.
2969 int match_end = pos + pattern_length;
2970 int new_pos = search.Search(subject, match_end);
2971 if (new_pos >= 0) {
2972 // A match.
2973 if (new_pos > match_end) {
2974 ReplacementStringBuilder::AddSubjectSlice(builder,
2975 match_end,
2976 new_pos);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002977 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002978 pos = new_pos;
2979 builder->Add(pattern_string);
2980 } else {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002981 break;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002982 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00002983 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002984
lrn@chromium.org25156de2010-04-06 13:10:27 +00002985 if (pos < max_search_start) {
2986 ReplacementStringBuilder::AddSubjectSlice(builder,
2987 pos + pattern_length,
2988 subject_length);
2989 }
2990 *match_pos = pos;
2991 return true;
2992}
2993
2994
2995static bool SearchStringMultiple(Handle<String> subject,
2996 Handle<String> pattern,
2997 Handle<JSArray> last_match_info,
2998 FixedArrayBuilder* builder) {
2999 ASSERT(subject->IsFlat());
3000 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003001
3002 // Treating as if a previous match was before first character.
3003 int match_pos = -pattern->length();
3004
3005 for (;;) { // Break when search complete.
3006 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3007 AssertNoAllocation no_gc;
3008 if (subject->IsAsciiRepresentation()) {
3009 Vector<const char> subject_vector = subject->ToAsciiVector();
3010 if (pattern->IsAsciiRepresentation()) {
3011 if (SearchStringMultiple(subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003012 pattern->ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003013 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003014 builder,
3015 &match_pos)) break;
3016 } else {
3017 if (SearchStringMultiple(subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003018 pattern->ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003019 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003020 builder,
3021 &match_pos)) break;
3022 }
3023 } else {
3024 Vector<const uc16> subject_vector = subject->ToUC16Vector();
3025 if (pattern->IsAsciiRepresentation()) {
3026 if (SearchStringMultiple(subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003027 pattern->ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003028 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003029 builder,
3030 &match_pos)) break;
3031 } else {
3032 if (SearchStringMultiple(subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003033 pattern->ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003034 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003035 builder,
3036 &match_pos)) break;
3037 }
3038 }
3039 }
3040
3041 if (match_pos >= 0) {
3042 SetLastMatchInfoNoCaptures(subject,
3043 last_match_info,
3044 match_pos,
3045 match_pos + pattern->length());
3046 return true;
3047 }
3048 return false; // No matches at all.
3049}
3050
3051
3052static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple(
3053 Handle<String> subject,
3054 Handle<JSRegExp> regexp,
3055 Handle<JSArray> last_match_array,
3056 FixedArrayBuilder* builder) {
3057 ASSERT(subject->IsFlat());
3058 int match_start = -1;
3059 int match_end = 0;
3060 int pos = 0;
3061 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3062 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3063
3064 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003065 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003066 int subject_length = subject->length();
3067
3068 for (;;) { // Break on failure, return on exception.
3069 RegExpImpl::IrregexpResult result =
3070 RegExpImpl::IrregexpExecOnce(regexp,
3071 subject,
3072 pos,
3073 register_vector);
3074 if (result == RegExpImpl::RE_SUCCESS) {
3075 match_start = register_vector[0];
3076 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3077 if (match_end < match_start) {
3078 ReplacementStringBuilder::AddSubjectSlice(builder,
3079 match_end,
3080 match_start);
3081 }
3082 match_end = register_vector[1];
3083 HandleScope loop_scope;
3084 builder->Add(*Factory::NewSubString(subject, match_start, match_end));
3085 if (match_start != match_end) {
3086 pos = match_end;
3087 } else {
3088 pos = match_end + 1;
3089 if (pos > subject_length) break;
3090 }
3091 } else if (result == RegExpImpl::RE_FAILURE) {
3092 break;
3093 } else {
3094 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3095 return result;
3096 }
3097 }
3098
3099 if (match_start >= 0) {
3100 if (match_end < subject_length) {
3101 ReplacementStringBuilder::AddSubjectSlice(builder,
3102 match_end,
3103 subject_length);
3104 }
3105 SetLastMatchInfoNoCaptures(subject,
3106 last_match_array,
3107 match_start,
3108 match_end);
3109 return RegExpImpl::RE_SUCCESS;
3110 } else {
3111 return RegExpImpl::RE_FAILURE; // No matches at all.
3112 }
3113}
3114
3115
3116static RegExpImpl::IrregexpResult SearchRegExpMultiple(
3117 Handle<String> subject,
3118 Handle<JSRegExp> regexp,
3119 Handle<JSArray> last_match_array,
3120 FixedArrayBuilder* builder) {
3121
3122 ASSERT(subject->IsFlat());
3123 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3124 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3125
3126 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003127 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003128
3129 RegExpImpl::IrregexpResult result =
3130 RegExpImpl::IrregexpExecOnce(regexp,
3131 subject,
3132 0,
3133 register_vector);
3134
3135 int capture_count = regexp->CaptureCount();
3136 int subject_length = subject->length();
3137
3138 // Position to search from.
3139 int pos = 0;
3140 // End of previous match. Differs from pos if match was empty.
3141 int match_end = 0;
3142 if (result == RegExpImpl::RE_SUCCESS) {
3143 // Need to keep a copy of the previous match for creating last_match_info
3144 // at the end, so we have two vectors that we swap between.
3145 OffsetsVector registers2(required_registers);
3146 Vector<int> prev_register_vector(registers2.vector(), registers2.length());
3147
3148 do {
3149 int match_start = register_vector[0];
3150 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3151 if (match_end < match_start) {
3152 ReplacementStringBuilder::AddSubjectSlice(builder,
3153 match_end,
3154 match_start);
3155 }
3156 match_end = register_vector[1];
3157
3158 {
3159 // Avoid accumulating new handles inside loop.
3160 HandleScope temp_scope;
3161 // Arguments array to replace function is match, captures, index and
3162 // subject, i.e., 3 + capture count in total.
3163 Handle<FixedArray> elements = Factory::NewFixedArray(3 + capture_count);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003164 Handle<String> match = Factory::NewSubString(subject,
3165 match_start,
3166 match_end);
3167 elements->set(0, *match);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003168 for (int i = 1; i <= capture_count; i++) {
3169 int start = register_vector[i * 2];
3170 if (start >= 0) {
3171 int end = register_vector[i * 2 + 1];
3172 ASSERT(start <= end);
3173 Handle<String> substring = Factory::NewSubString(subject,
3174 start,
3175 end);
3176 elements->set(i, *substring);
3177 } else {
3178 ASSERT(register_vector[i * 2 + 1] < 0);
3179 elements->set(i, Heap::undefined_value());
3180 }
3181 }
3182 elements->set(capture_count + 1, Smi::FromInt(match_start));
3183 elements->set(capture_count + 2, *subject);
3184 builder->Add(*Factory::NewJSArrayWithElements(elements));
3185 }
3186 // Swap register vectors, so the last successful match is in
3187 // prev_register_vector.
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003188 Vector<int32_t> tmp = prev_register_vector;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003189 prev_register_vector = register_vector;
3190 register_vector = tmp;
3191
3192 if (match_end > match_start) {
3193 pos = match_end;
3194 } else {
3195 pos = match_end + 1;
3196 if (pos > subject_length) {
3197 break;
3198 }
3199 }
3200
3201 result = RegExpImpl::IrregexpExecOnce(regexp,
3202 subject,
3203 pos,
3204 register_vector);
3205 } while (result == RegExpImpl::RE_SUCCESS);
3206
3207 if (result != RegExpImpl::RE_EXCEPTION) {
3208 // Finished matching, with at least one match.
3209 if (match_end < subject_length) {
3210 ReplacementStringBuilder::AddSubjectSlice(builder,
3211 match_end,
3212 subject_length);
3213 }
3214
3215 int last_match_capture_count = (capture_count + 1) * 2;
3216 int last_match_array_size =
3217 last_match_capture_count + RegExpImpl::kLastMatchOverhead;
3218 last_match_array->EnsureSize(last_match_array_size);
3219 AssertNoAllocation no_gc;
3220 FixedArray* elements = FixedArray::cast(last_match_array->elements());
3221 RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count);
3222 RegExpImpl::SetLastSubject(elements, *subject);
3223 RegExpImpl::SetLastInput(elements, *subject);
3224 for (int i = 0; i < last_match_capture_count; i++) {
3225 RegExpImpl::SetCapture(elements, i, prev_register_vector[i]);
3226 }
3227 return RegExpImpl::RE_SUCCESS;
3228 }
3229 }
3230 // No matches at all, return failure or exception result directly.
3231 return result;
3232}
3233
3234
lrn@chromium.org303ada72010-10-27 09:33:13 +00003235static MaybeObject* Runtime_RegExpExecMultiple(Arguments args) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003236 ASSERT(args.length() == 4);
3237 HandleScope handles;
3238
3239 CONVERT_ARG_CHECKED(String, subject, 1);
3240 if (!subject->IsFlat()) { FlattenString(subject); }
3241 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
3242 CONVERT_ARG_CHECKED(JSArray, last_match_info, 2);
3243 CONVERT_ARG_CHECKED(JSArray, result_array, 3);
3244
3245 ASSERT(last_match_info->HasFastElements());
3246 ASSERT(regexp->GetFlags().is_global());
3247 Handle<FixedArray> result_elements;
3248 if (result_array->HasFastElements()) {
3249 result_elements =
3250 Handle<FixedArray>(FixedArray::cast(result_array->elements()));
3251 } else {
3252 result_elements = Factory::NewFixedArrayWithHoles(16);
3253 }
3254 FixedArrayBuilder builder(result_elements);
3255
3256 if (regexp->TypeTag() == JSRegExp::ATOM) {
3257 Handle<String> pattern(
3258 String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex)));
lrn@chromium.org25156de2010-04-06 13:10:27 +00003259 if (!pattern->IsFlat()) FlattenString(pattern);
3260 if (SearchStringMultiple(subject, pattern, last_match_info, &builder)) {
3261 return *builder.ToJSArray(result_array);
3262 }
3263 return Heap::null_value();
3264 }
3265
3266 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
3267
3268 RegExpImpl::IrregexpResult result;
3269 if (regexp->CaptureCount() == 0) {
3270 result = SearchRegExpNoCaptureMultiple(subject,
3271 regexp,
3272 last_match_info,
3273 &builder);
3274 } else {
3275 result = SearchRegExpMultiple(subject, regexp, last_match_info, &builder);
3276 }
3277 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array);
3278 if (result == RegExpImpl::RE_FAILURE) return Heap::null_value();
3279 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3280 return Failure::Exception();
3281}
3282
3283
lrn@chromium.org303ada72010-10-27 09:33:13 +00003284static MaybeObject* Runtime_NumberToRadixString(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003285 NoHandleAllocation ha;
3286 ASSERT(args.length() == 2);
3287
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003288 // Fast case where the result is a one character string.
3289 if (args[0]->IsSmi() && args[1]->IsSmi()) {
3290 int value = Smi::cast(args[0])->value();
3291 int radix = Smi::cast(args[1])->value();
3292 if (value >= 0 && value < radix) {
3293 RUNTIME_ASSERT(radix <= 36);
3294 // Character array used for conversion.
3295 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
3296 return Heap::LookupSingleCharacterStringFromCode(kCharTable[value]);
3297 }
3298 }
3299
3300 // Slow case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003301 CONVERT_DOUBLE_CHECKED(value, args[0]);
3302 if (isnan(value)) {
3303 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
3304 }
3305 if (isinf(value)) {
3306 if (value < 0) {
3307 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
3308 }
3309 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
3310 }
3311 CONVERT_DOUBLE_CHECKED(radix_number, args[1]);
3312 int radix = FastD2I(radix_number);
3313 RUNTIME_ASSERT(2 <= radix && radix <= 36);
3314 char* str = DoubleToRadixCString(value, radix);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003315 MaybeObject* result = Heap::AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003316 DeleteArray(str);
3317 return result;
3318}
3319
3320
lrn@chromium.org303ada72010-10-27 09:33:13 +00003321static MaybeObject* Runtime_NumberToFixed(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003322 NoHandleAllocation ha;
3323 ASSERT(args.length() == 2);
3324
3325 CONVERT_DOUBLE_CHECKED(value, args[0]);
3326 if (isnan(value)) {
3327 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
3328 }
3329 if (isinf(value)) {
3330 if (value < 0) {
3331 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
3332 }
3333 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
3334 }
3335 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3336 int f = FastD2I(f_number);
3337 RUNTIME_ASSERT(f >= 0);
3338 char* str = DoubleToFixedCString(value, f);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003339 MaybeObject* result = Heap::AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003340 DeleteArray(str);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003341 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003342}
3343
3344
lrn@chromium.org303ada72010-10-27 09:33:13 +00003345static MaybeObject* Runtime_NumberToExponential(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003346 NoHandleAllocation ha;
3347 ASSERT(args.length() == 2);
3348
3349 CONVERT_DOUBLE_CHECKED(value, args[0]);
3350 if (isnan(value)) {
3351 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
3352 }
3353 if (isinf(value)) {
3354 if (value < 0) {
3355 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
3356 }
3357 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
3358 }
3359 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3360 int f = FastD2I(f_number);
3361 RUNTIME_ASSERT(f >= -1 && f <= 20);
3362 char* str = DoubleToExponentialCString(value, f);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003363 MaybeObject* result = Heap::AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003364 DeleteArray(str);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003365 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003366}
3367
3368
lrn@chromium.org303ada72010-10-27 09:33:13 +00003369static MaybeObject* Runtime_NumberToPrecision(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003370 NoHandleAllocation ha;
3371 ASSERT(args.length() == 2);
3372
3373 CONVERT_DOUBLE_CHECKED(value, args[0]);
3374 if (isnan(value)) {
3375 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
3376 }
3377 if (isinf(value)) {
3378 if (value < 0) {
3379 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
3380 }
3381 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
3382 }
3383 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3384 int f = FastD2I(f_number);
3385 RUNTIME_ASSERT(f >= 1 && f <= 21);
3386 char* str = DoubleToPrecisionCString(value, f);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003387 MaybeObject* result = Heap::AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003388 DeleteArray(str);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003389 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003390}
3391
3392
3393// Returns a single character string where first character equals
3394// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003395static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003396 if (index < static_cast<uint32_t>(string->length())) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003397 string->TryFlatten();
ager@chromium.org870a0b62008-11-04 11:43:05 +00003398 return LookupSingleCharacterStringFromCode(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003399 string->Get(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003400 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003401 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003402}
3403
3404
lrn@chromium.org303ada72010-10-27 09:33:13 +00003405MaybeObject* Runtime::GetElementOrCharAt(Handle<Object> object,
3406 uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003407 // Handle [] indexing on Strings
3408 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003409 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
3410 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003411 }
3412
3413 // Handle [] indexing on String objects
3414 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003415 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
3416 Handle<Object> result =
3417 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
3418 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003419 }
3420
3421 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003422 Handle<Object> prototype = GetPrototype(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003423 return prototype->GetElement(index);
3424 }
3425
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003426 return GetElement(object, index);
3427}
3428
3429
lrn@chromium.org303ada72010-10-27 09:33:13 +00003430MaybeObject* Runtime::GetElement(Handle<Object> object, uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003431 return object->GetElement(index);
3432}
3433
3434
lrn@chromium.org303ada72010-10-27 09:33:13 +00003435MaybeObject* Runtime::GetObjectProperty(Handle<Object> object,
3436 Handle<Object> key) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003437 HandleScope scope;
3438
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003439 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003440 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003441 Handle<Object> error =
3442 Factory::NewTypeError("non_object_property_load",
3443 HandleVector(args, 2));
3444 return Top::Throw(*error);
3445 }
3446
3447 // Check if the given key is an array index.
3448 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003449 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003450 return GetElementOrCharAt(object, index);
3451 }
3452
3453 // Convert the key to a string - possibly by calling back into JavaScript.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003454 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003455 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003456 name = Handle<String>::cast(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003457 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003458 bool has_pending_exception = false;
3459 Handle<Object> converted =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003460 Execution::ToString(key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003461 if (has_pending_exception) return Failure::Exception();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003462 name = Handle<String>::cast(converted);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003463 }
3464
ager@chromium.org32912102009-01-16 10:38:43 +00003465 // Check if the name is trivially convertible to an index and get
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003466 // the element if so.
3467 if (name->AsArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003468 return GetElementOrCharAt(object, index);
3469 } else {
3470 PropertyAttributes attr;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003471 return object->GetProperty(*name, &attr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003472 }
3473}
3474
3475
lrn@chromium.org303ada72010-10-27 09:33:13 +00003476static MaybeObject* Runtime_GetProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003477 NoHandleAllocation ha;
3478 ASSERT(args.length() == 2);
3479
3480 Handle<Object> object = args.at<Object>(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003481 Handle<Object> key = args.at<Object>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003482
3483 return Runtime::GetObjectProperty(object, key);
3484}
3485
3486
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003487// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003488static MaybeObject* Runtime_KeyedGetProperty(Arguments args) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00003489 NoHandleAllocation ha;
3490 ASSERT(args.length() == 2);
3491
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003492 // Fast cases for getting named properties of the receiver JSObject
ager@chromium.org8bb60582008-12-11 12:02:20 +00003493 // itself.
3494 //
3495 // The global proxy objects has to be excluded since LocalLookup on
ager@chromium.org32912102009-01-16 10:38:43 +00003496 // the global proxy object can return a valid result even though the
ager@chromium.org8bb60582008-12-11 12:02:20 +00003497 // global proxy object never has properties. This is the case
3498 // because the global proxy object forwards everything to its hidden
3499 // prototype including local lookups.
3500 //
3501 // Additionally, we need to make sure that we do not cache results
3502 // for objects that require access checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003503 if (args[0]->IsJSObject() &&
3504 !args[0]->IsJSGlobalProxy() &&
ager@chromium.org8bb60582008-12-11 12:02:20 +00003505 !args[0]->IsAccessCheckNeeded() &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003506 args[1]->IsString()) {
3507 JSObject* receiver = JSObject::cast(args[0]);
3508 String* key = String::cast(args[1]);
3509 if (receiver->HasFastProperties()) {
3510 // Attempt to use lookup cache.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003511 Map* receiver_map = receiver->map();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00003512 int offset = KeyedLookupCache::Lookup(receiver_map, key);
3513 if (offset != -1) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003514 Object* value = receiver->FastPropertyAt(offset);
3515 return value->IsTheHole() ? Heap::undefined_value() : value;
3516 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003517 // Lookup cache miss. Perform lookup and update the cache if appropriate.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003518 LookupResult result;
3519 receiver->LocalLookup(key, &result);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00003520 if (result.IsProperty() && result.type() == FIELD) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003521 int offset = result.GetFieldIndex();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00003522 KeyedLookupCache::Update(receiver_map, key, offset);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003523 return receiver->FastPropertyAt(offset);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003524 }
3525 } else {
3526 // Attempt dictionary lookup.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00003527 StringDictionary* dictionary = receiver->property_dictionary();
3528 int entry = dictionary->FindEntry(key);
3529 if ((entry != StringDictionary::kNotFound) &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003530 (dictionary->DetailsAt(entry).type() == NORMAL)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003531 Object* value = dictionary->ValueAt(entry);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003532 if (!receiver->IsGlobalObject()) return value;
3533 value = JSGlobalPropertyCell::cast(value)->value();
3534 if (!value->IsTheHole()) return value;
3535 // If value is the hole do the general lookup.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003536 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00003537 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003538 } else if (args[0]->IsString() && args[1]->IsSmi()) {
3539 // Fast case for string indexing using [] with a smi index.
3540 HandleScope scope;
3541 Handle<String> str = args.at<String>(0);
3542 int index = Smi::cast(args[1])->value();
3543 Handle<Object> result = GetCharAt(str, index);
3544 return *result;
ager@chromium.org7c537e22008-10-16 08:43:32 +00003545 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003546
3547 // Fall back to GetObjectProperty.
ager@chromium.org7c537e22008-10-16 08:43:32 +00003548 return Runtime::GetObjectProperty(args.at<Object>(0),
3549 args.at<Object>(1));
3550}
3551
3552
lrn@chromium.org303ada72010-10-27 09:33:13 +00003553static MaybeObject* Runtime_DefineOrRedefineAccessorProperty(Arguments args) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003554 ASSERT(args.length() == 5);
3555 HandleScope scope;
3556 CONVERT_ARG_CHECKED(JSObject, obj, 0);
3557 CONVERT_CHECKED(String, name, args[1]);
3558 CONVERT_CHECKED(Smi, flag_setter, args[2]);
3559 CONVERT_CHECKED(JSFunction, fun, args[3]);
3560 CONVERT_CHECKED(Smi, flag_attr, args[4]);
3561 int unchecked = flag_attr->value();
3562 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3563 RUNTIME_ASSERT(!obj->IsNull());
3564 LookupResult result;
3565 obj->LocalLookupRealNamedProperty(name, &result);
3566
3567 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
3568 // If an existing property is either FIELD, NORMAL or CONSTANT_FUNCTION
3569 // delete it to avoid running into trouble in DefineAccessor, which
3570 // handles this incorrectly if the property is readonly (does nothing)
3571 if (result.IsProperty() &&
3572 (result.type() == FIELD || result.type() == NORMAL
3573 || result.type() == CONSTANT_FUNCTION)) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003574 Object* ok;
3575 { MaybeObject* maybe_ok =
3576 obj->DeleteProperty(name, JSObject::NORMAL_DELETION);
3577 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
3578 }
ager@chromium.org5c838252010-02-19 08:53:10 +00003579 }
3580 return obj->DefineAccessor(name, flag_setter->value() == 0, fun, attr);
3581}
3582
lrn@chromium.org303ada72010-10-27 09:33:13 +00003583static MaybeObject* Runtime_DefineOrRedefineDataProperty(Arguments args) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003584 ASSERT(args.length() == 4);
3585 HandleScope scope;
3586 CONVERT_ARG_CHECKED(JSObject, js_object, 0);
3587 CONVERT_ARG_CHECKED(String, name, 1);
3588 Handle<Object> obj_value = args.at<Object>(2);
3589
3590 CONVERT_CHECKED(Smi, flag, args[3]);
3591 int unchecked = flag->value();
3592 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3593
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003594 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
3595
3596 // Check if this is an element.
3597 uint32_t index;
3598 bool is_element = name->AsArrayIndex(&index);
3599
3600 // Special case for elements if any of the flags are true.
3601 // If elements are in fast case we always implicitly assume that:
3602 // DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
3603 if (((unchecked & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0) &&
3604 is_element) {
3605 // Normalize the elements to enable attributes on the property.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003606 NormalizeElements(js_object);
3607 Handle<NumberDictionary> dictionary(js_object->element_dictionary());
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003608 // Make sure that we never go back to fast case.
3609 dictionary->set_requires_slow_elements();
3610 PropertyDetails details = PropertyDetails(attr, NORMAL);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003611 NumberDictionarySet(dictionary, index, obj_value, details);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003612 }
3613
ager@chromium.org5c838252010-02-19 08:53:10 +00003614 LookupResult result;
3615 js_object->LocalLookupRealNamedProperty(*name, &result);
3616
ager@chromium.org5c838252010-02-19 08:53:10 +00003617 // Take special care when attributes are different and there is already
3618 // a property. For simplicity we normalize the property which enables us
3619 // to not worry about changing the instance_descriptor and creating a new
3620 // map. The current version of SetObjectProperty does not handle attributes
3621 // correctly in the case where a property is a field and is reset with
3622 // new attributes.
3623 if (result.IsProperty() && attr != result.GetAttributes()) {
3624 // New attributes - normalize to avoid writing to instance descriptor
lrn@chromium.org303ada72010-10-27 09:33:13 +00003625 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00003626 // Use IgnoreAttributes version since a readonly property may be
3627 // overridden and SetProperty does not allow this.
3628 return js_object->IgnoreAttributesAndSetLocalProperty(*name,
3629 *obj_value,
3630 attr);
3631 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003632
ager@chromium.org5c838252010-02-19 08:53:10 +00003633 return Runtime::SetObjectProperty(js_object, name, obj_value, attr);
3634}
3635
3636
lrn@chromium.org303ada72010-10-27 09:33:13 +00003637MaybeObject* Runtime::SetObjectProperty(Handle<Object> object,
3638 Handle<Object> key,
3639 Handle<Object> value,
3640 PropertyAttributes attr) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003641 HandleScope scope;
3642
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003643 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003644 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003645 Handle<Object> error =
3646 Factory::NewTypeError("non_object_property_store",
3647 HandleVector(args, 2));
3648 return Top::Throw(*error);
3649 }
3650
3651 // If the object isn't a JavaScript object, we ignore the store.
3652 if (!object->IsJSObject()) return *value;
3653
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003654 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
3655
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003656 // Check if the given key is an array index.
3657 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003658 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003659 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
3660 // of a string using [] notation. We need to support this too in
3661 // JavaScript.
3662 // In the case of a String object we just need to redirect the assignment to
3663 // the underlying string if the index is in range. Since the underlying
3664 // string does nothing with the assignment then we can ignore such
3665 // assignments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003666 if (js_object->IsStringObjectWithCharacterAt(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003667 return *value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003668 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003669
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003670 Handle<Object> result = SetElement(js_object, index, value);
3671 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003672 return *value;
3673 }
3674
3675 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003676 Handle<Object> result;
3677 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003678 result = SetElement(js_object, index, value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003679 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003680 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003681 key_string->TryFlatten();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003682 result = SetProperty(js_object, key_string, value, attr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003683 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003684 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003685 return *value;
3686 }
3687
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003688 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003689 bool has_pending_exception = false;
3690 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
3691 if (has_pending_exception) return Failure::Exception();
3692 Handle<String> name = Handle<String>::cast(converted);
3693
3694 if (name->AsArrayIndex(&index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003695 return js_object->SetElement(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003696 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003697 return js_object->SetProperty(*name, *value, attr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003698 }
3699}
3700
3701
lrn@chromium.org303ada72010-10-27 09:33:13 +00003702MaybeObject* Runtime::ForceSetObjectProperty(Handle<JSObject> js_object,
3703 Handle<Object> key,
3704 Handle<Object> value,
3705 PropertyAttributes attr) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +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.org65dad4b2009-04-23 08:48:43 +00003711 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
3712 // of a string using [] notation. We need to support this too in
3713 // JavaScript.
3714 // In the case of a String object we just need to redirect the assignment to
3715 // the underlying string if the index is in range. Since the underlying
3716 // string does nothing with the assignment then we can ignore such
3717 // assignments.
3718 if (js_object->IsStringObjectWithCharacterAt(index)) {
3719 return *value;
3720 }
3721
3722 return js_object->SetElement(index, *value);
3723 }
3724
3725 if (key->IsString()) {
3726 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003727 return js_object->SetElement(index, *value);
3728 } else {
3729 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003730 key_string->TryFlatten();
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003731 return js_object->IgnoreAttributesAndSetLocalProperty(*key_string,
3732 *value,
3733 attr);
3734 }
3735 }
3736
3737 // Call-back into JavaScript to convert the key to a string.
3738 bool has_pending_exception = false;
3739 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
3740 if (has_pending_exception) return Failure::Exception();
3741 Handle<String> name = Handle<String>::cast(converted);
3742
3743 if (name->AsArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003744 return js_object->SetElement(index, *value);
3745 } else {
3746 return js_object->IgnoreAttributesAndSetLocalProperty(*name, *value, attr);
3747 }
3748}
3749
3750
lrn@chromium.org303ada72010-10-27 09:33:13 +00003751MaybeObject* Runtime::ForceDeleteObjectProperty(Handle<JSObject> js_object,
3752 Handle<Object> key) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00003753 HandleScope scope;
3754
3755 // Check if the given key is an array index.
3756 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003757 if (key->ToArrayIndex(&index)) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00003758 // In Firefox/SpiderMonkey, Safari and Opera you can access the
3759 // characters of a string using [] notation. In the case of a
3760 // String object we just need to redirect the deletion to the
3761 // underlying string if the index is in range. Since the
3762 // underlying string does nothing with the deletion, we can ignore
3763 // such deletions.
3764 if (js_object->IsStringObjectWithCharacterAt(index)) {
3765 return Heap::true_value();
3766 }
3767
3768 return js_object->DeleteElement(index, JSObject::FORCE_DELETION);
3769 }
3770
3771 Handle<String> key_string;
3772 if (key->IsString()) {
3773 key_string = Handle<String>::cast(key);
3774 } else {
3775 // Call-back into JavaScript to convert the key to a string.
3776 bool has_pending_exception = false;
3777 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
3778 if (has_pending_exception) return Failure::Exception();
3779 key_string = Handle<String>::cast(converted);
3780 }
3781
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003782 key_string->TryFlatten();
ager@chromium.orge2902be2009-06-08 12:21:35 +00003783 return js_object->DeleteProperty(*key_string, JSObject::FORCE_DELETION);
3784}
3785
3786
lrn@chromium.org303ada72010-10-27 09:33:13 +00003787static MaybeObject* Runtime_SetProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003788 NoHandleAllocation ha;
3789 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
3790
3791 Handle<Object> object = args.at<Object>(0);
3792 Handle<Object> key = args.at<Object>(1);
3793 Handle<Object> value = args.at<Object>(2);
3794
3795 // Compute attributes.
3796 PropertyAttributes attributes = NONE;
3797 if (args.length() == 4) {
3798 CONVERT_CHECKED(Smi, value_obj, args[3]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003799 int unchecked_value = value_obj->value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003800 // Only attribute bits should be set.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003801 RUNTIME_ASSERT(
3802 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3803 attributes = static_cast<PropertyAttributes>(unchecked_value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003804 }
3805 return Runtime::SetObjectProperty(object, key, value, attributes);
3806}
3807
3808
3809// Set a local property, even if it is READ_ONLY. If the property does not
3810// exist, it will be added with attributes NONE.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003811static MaybeObject* Runtime_IgnoreAttributesAndSetProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003812 NoHandleAllocation ha;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003813 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003814 CONVERT_CHECKED(JSObject, object, args[0]);
3815 CONVERT_CHECKED(String, name, args[1]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003816 // Compute attributes.
3817 PropertyAttributes attributes = NONE;
3818 if (args.length() == 4) {
3819 CONVERT_CHECKED(Smi, value_obj, args[3]);
3820 int unchecked_value = value_obj->value();
3821 // Only attribute bits should be set.
3822 RUNTIME_ASSERT(
3823 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3824 attributes = static_cast<PropertyAttributes>(unchecked_value);
3825 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003826
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003827 return object->
3828 IgnoreAttributesAndSetLocalProperty(name, args[2], attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003829}
3830
3831
lrn@chromium.org303ada72010-10-27 09:33:13 +00003832static MaybeObject* Runtime_DeleteProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003833 NoHandleAllocation ha;
3834 ASSERT(args.length() == 2);
3835
3836 CONVERT_CHECKED(JSObject, object, args[0]);
3837 CONVERT_CHECKED(String, key, args[1]);
ager@chromium.orge2902be2009-06-08 12:21:35 +00003838 return object->DeleteProperty(key, JSObject::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003839}
3840
3841
ager@chromium.org9085a012009-05-11 19:22:57 +00003842static Object* HasLocalPropertyImplementation(Handle<JSObject> object,
3843 Handle<String> key) {
3844 if (object->HasLocalProperty(*key)) return Heap::true_value();
3845 // Handle hidden prototypes. If there's a hidden prototype above this thing
3846 // then we have to check it for properties, because they are supposed to
3847 // look like they are on this object.
3848 Handle<Object> proto(object->GetPrototype());
3849 if (proto->IsJSObject() &&
3850 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
3851 return HasLocalPropertyImplementation(Handle<JSObject>::cast(proto), key);
3852 }
3853 return Heap::false_value();
3854}
3855
3856
lrn@chromium.org303ada72010-10-27 09:33:13 +00003857static MaybeObject* Runtime_HasLocalProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003858 NoHandleAllocation ha;
3859 ASSERT(args.length() == 2);
3860 CONVERT_CHECKED(String, key, args[1]);
3861
ager@chromium.org9085a012009-05-11 19:22:57 +00003862 Object* obj = args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003863 // Only JS objects can have properties.
ager@chromium.org9085a012009-05-11 19:22:57 +00003864 if (obj->IsJSObject()) {
3865 JSObject* object = JSObject::cast(obj);
3866 // Fast case - no interceptors.
3867 if (object->HasRealNamedProperty(key)) return Heap::true_value();
3868 // Slow case. Either it's not there or we have an interceptor. We should
3869 // have handles for this kind of deal.
3870 HandleScope scope;
3871 return HasLocalPropertyImplementation(Handle<JSObject>(object),
3872 Handle<String>(key));
3873 } else if (obj->IsString()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003874 // Well, there is one exception: Handle [] on strings.
3875 uint32_t index;
3876 if (key->AsArrayIndex(&index)) {
ager@chromium.org9085a012009-05-11 19:22:57 +00003877 String* string = String::cast(obj);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003878 if (index < static_cast<uint32_t>(string->length()))
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003879 return Heap::true_value();
3880 }
3881 }
3882 return Heap::false_value();
3883}
3884
3885
lrn@chromium.org303ada72010-10-27 09:33:13 +00003886static MaybeObject* Runtime_HasProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003887 NoHandleAllocation na;
3888 ASSERT(args.length() == 2);
3889
3890 // Only JS objects can have properties.
3891 if (args[0]->IsJSObject()) {
3892 JSObject* object = JSObject::cast(args[0]);
3893 CONVERT_CHECKED(String, key, args[1]);
3894 if (object->HasProperty(key)) return Heap::true_value();
3895 }
3896 return Heap::false_value();
3897}
3898
3899
lrn@chromium.org303ada72010-10-27 09:33:13 +00003900static MaybeObject* Runtime_HasElement(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003901 NoHandleAllocation na;
3902 ASSERT(args.length() == 2);
3903
3904 // Only JS objects can have elements.
3905 if (args[0]->IsJSObject()) {
3906 JSObject* object = JSObject::cast(args[0]);
3907 CONVERT_CHECKED(Smi, index_obj, args[1]);
3908 uint32_t index = index_obj->value();
3909 if (object->HasElement(index)) return Heap::true_value();
3910 }
3911 return Heap::false_value();
3912}
3913
3914
lrn@chromium.org303ada72010-10-27 09:33:13 +00003915static MaybeObject* Runtime_IsPropertyEnumerable(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003916 NoHandleAllocation ha;
3917 ASSERT(args.length() == 2);
3918
3919 CONVERT_CHECKED(JSObject, object, args[0]);
3920 CONVERT_CHECKED(String, key, args[1]);
3921
3922 uint32_t index;
3923 if (key->AsArrayIndex(&index)) {
3924 return Heap::ToBoolean(object->HasElement(index));
3925 }
3926
ager@chromium.org870a0b62008-11-04 11:43:05 +00003927 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
3928 return Heap::ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003929}
3930
3931
lrn@chromium.org303ada72010-10-27 09:33:13 +00003932static MaybeObject* Runtime_GetPropertyNames(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003933 HandleScope scope;
3934 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00003935 CONVERT_ARG_CHECKED(JSObject, object, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003936 return *GetKeysFor(object);
3937}
3938
3939
3940// Returns either a FixedArray as Runtime_GetPropertyNames,
3941// or, if the given object has an enum cache that contains
3942// all enumerable properties of the object and its prototypes
3943// have none, the map of the object. This is used to speed up
3944// the check for deletions during a for-in.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003945static MaybeObject* Runtime_GetPropertyNamesFast(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003946 ASSERT(args.length() == 1);
3947
3948 CONVERT_CHECKED(JSObject, raw_object, args[0]);
3949
3950 if (raw_object->IsSimpleEnum()) return raw_object->map();
3951
3952 HandleScope scope;
3953 Handle<JSObject> object(raw_object);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00003954 Handle<FixedArray> content = GetKeysInFixedArrayFor(object,
3955 INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003956
3957 // Test again, since cache may have been built by preceding call.
3958 if (object->IsSimpleEnum()) return object->map();
3959
3960 return *content;
3961}
3962
3963
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003964// Find the length of the prototype chain that is to to handled as one. If a
3965// prototype object is hidden it is to be viewed as part of the the object it
3966// is prototype for.
3967static int LocalPrototypeChainLength(JSObject* obj) {
3968 int count = 1;
3969 Object* proto = obj->GetPrototype();
3970 while (proto->IsJSObject() &&
3971 JSObject::cast(proto)->map()->is_hidden_prototype()) {
3972 count++;
3973 proto = JSObject::cast(proto)->GetPrototype();
3974 }
3975 return count;
3976}
3977
3978
3979// Return the names of the local named properties.
3980// args[0]: object
lrn@chromium.org303ada72010-10-27 09:33:13 +00003981static MaybeObject* Runtime_GetLocalPropertyNames(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003982 HandleScope scope;
3983 ASSERT(args.length() == 1);
3984 if (!args[0]->IsJSObject()) {
3985 return Heap::undefined_value();
3986 }
3987 CONVERT_ARG_CHECKED(JSObject, obj, 0);
3988
3989 // Skip the global proxy as it has no properties and always delegates to the
3990 // real global object.
3991 if (obj->IsJSGlobalProxy()) {
3992 // Only collect names if access is permitted.
3993 if (obj->IsAccessCheckNeeded() &&
3994 !Top::MayNamedAccess(*obj, Heap::undefined_value(), v8::ACCESS_KEYS)) {
3995 Top::ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
3996 return *Factory::NewJSArray(0);
3997 }
3998 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
3999 }
4000
4001 // Find the number of objects making up this.
4002 int length = LocalPrototypeChainLength(*obj);
4003
4004 // Find the number of local properties for each of the objects.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00004005 ScopedVector<int> local_property_count(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004006 int total_property_count = 0;
4007 Handle<JSObject> jsproto = obj;
4008 for (int i = 0; i < length; i++) {
4009 // Only collect names if access is permitted.
4010 if (jsproto->IsAccessCheckNeeded() &&
4011 !Top::MayNamedAccess(*jsproto,
4012 Heap::undefined_value(),
4013 v8::ACCESS_KEYS)) {
4014 Top::ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
4015 return *Factory::NewJSArray(0);
4016 }
4017 int n;
4018 n = jsproto->NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE));
4019 local_property_count[i] = n;
4020 total_property_count += n;
4021 if (i < length - 1) {
4022 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4023 }
4024 }
4025
4026 // Allocate an array with storage for all the property names.
4027 Handle<FixedArray> names = Factory::NewFixedArray(total_property_count);
4028
4029 // Get the property names.
4030 jsproto = obj;
4031 int proto_with_hidden_properties = 0;
4032 for (int i = 0; i < length; i++) {
4033 jsproto->GetLocalPropertyNames(*names,
4034 i == 0 ? 0 : local_property_count[i - 1]);
4035 if (!GetHiddenProperties(jsproto, false)->IsUndefined()) {
4036 proto_with_hidden_properties++;
4037 }
4038 if (i < length - 1) {
4039 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4040 }
4041 }
4042
4043 // Filter out name of hidden propeties object.
4044 if (proto_with_hidden_properties > 0) {
4045 Handle<FixedArray> old_names = names;
4046 names = Factory::NewFixedArray(
4047 names->length() - proto_with_hidden_properties);
4048 int dest_pos = 0;
4049 for (int i = 0; i < total_property_count; i++) {
4050 Object* name = old_names->get(i);
4051 if (name == Heap::hidden_symbol()) {
4052 continue;
4053 }
4054 names->set(dest_pos++, name);
4055 }
4056 }
4057
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004058 return *Factory::NewJSArrayWithElements(names);
4059}
4060
4061
4062// Return the names of the local indexed properties.
4063// args[0]: object
lrn@chromium.org303ada72010-10-27 09:33:13 +00004064static MaybeObject* Runtime_GetLocalElementNames(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004065 HandleScope scope;
4066 ASSERT(args.length() == 1);
4067 if (!args[0]->IsJSObject()) {
4068 return Heap::undefined_value();
4069 }
4070 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4071
4072 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
4073 Handle<FixedArray> names = Factory::NewFixedArray(n);
4074 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
4075 return *Factory::NewJSArrayWithElements(names);
4076}
4077
4078
4079// Return information on whether an object has a named or indexed interceptor.
4080// args[0]: object
lrn@chromium.org303ada72010-10-27 09:33:13 +00004081static MaybeObject* Runtime_GetInterceptorInfo(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004082 HandleScope scope;
4083 ASSERT(args.length() == 1);
4084 if (!args[0]->IsJSObject()) {
4085 return Smi::FromInt(0);
4086 }
4087 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4088
4089 int result = 0;
4090 if (obj->HasNamedInterceptor()) result |= 2;
4091 if (obj->HasIndexedInterceptor()) result |= 1;
4092
4093 return Smi::FromInt(result);
4094}
4095
4096
4097// Return property names from named interceptor.
4098// args[0]: object
lrn@chromium.org303ada72010-10-27 09:33:13 +00004099static MaybeObject* Runtime_GetNamedInterceptorPropertyNames(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004100 HandleScope scope;
4101 ASSERT(args.length() == 1);
4102 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4103
4104 if (obj->HasNamedInterceptor()) {
4105 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
4106 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4107 }
4108 return Heap::undefined_value();
4109}
4110
4111
4112// Return element names from indexed interceptor.
4113// args[0]: object
lrn@chromium.org303ada72010-10-27 09:33:13 +00004114static MaybeObject* Runtime_GetIndexedInterceptorElementNames(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004115 HandleScope scope;
4116 ASSERT(args.length() == 1);
4117 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4118
4119 if (obj->HasIndexedInterceptor()) {
4120 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
4121 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4122 }
4123 return Heap::undefined_value();
4124}
4125
4126
lrn@chromium.org303ada72010-10-27 09:33:13 +00004127static MaybeObject* Runtime_LocalKeys(Arguments args) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004128 ASSERT_EQ(args.length(), 1);
4129 CONVERT_CHECKED(JSObject, raw_object, args[0]);
4130 HandleScope scope;
4131 Handle<JSObject> object(raw_object);
4132 Handle<FixedArray> contents = GetKeysInFixedArrayFor(object,
4133 LOCAL_ONLY);
4134 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
4135 // property array and since the result is mutable we have to create
4136 // a fresh clone on each invocation.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004137 int length = contents->length();
4138 Handle<FixedArray> copy = Factory::NewFixedArray(length);
4139 for (int i = 0; i < length; i++) {
4140 Object* entry = contents->get(i);
4141 if (entry->IsString()) {
4142 copy->set(i, entry);
4143 } else {
4144 ASSERT(entry->IsNumber());
4145 HandleScope scope;
4146 Handle<Object> entry_handle(entry);
4147 Handle<Object> entry_str = Factory::NumberToString(entry_handle);
4148 copy->set(i, *entry_str);
4149 }
4150 }
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004151 return *Factory::NewJSArrayWithElements(copy);
4152}
4153
4154
lrn@chromium.org303ada72010-10-27 09:33:13 +00004155static MaybeObject* Runtime_GetArgumentsProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004156 NoHandleAllocation ha;
4157 ASSERT(args.length() == 1);
4158
4159 // Compute the frame holding the arguments.
4160 JavaScriptFrameIterator it;
4161 it.AdvanceToArgumentsFrame();
4162 JavaScriptFrame* frame = it.frame();
4163
4164 // Get the actual number of provided arguments.
4165 const uint32_t n = frame->GetProvidedParametersCount();
4166
4167 // Try to convert the key to an index. If successful and within
4168 // index return the the argument from the frame.
4169 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004170 if (args[0]->ToArrayIndex(&index) && index < n) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004171 return frame->GetParameter(index);
4172 }
4173
4174 // Convert the key to a string.
4175 HandleScope scope;
4176 bool exception = false;
4177 Handle<Object> converted =
4178 Execution::ToString(args.at<Object>(0), &exception);
4179 if (exception) return Failure::Exception();
4180 Handle<String> key = Handle<String>::cast(converted);
4181
4182 // Try to convert the string key into an array index.
4183 if (key->AsArrayIndex(&index)) {
4184 if (index < n) {
4185 return frame->GetParameter(index);
4186 } else {
4187 return Top::initial_object_prototype()->GetElement(index);
4188 }
4189 }
4190
4191 // Handle special arguments properties.
4192 if (key->Equals(Heap::length_symbol())) return Smi::FromInt(n);
4193 if (key->Equals(Heap::callee_symbol())) return frame->function();
4194
4195 // Lookup in the initial Object.prototype object.
4196 return Top::initial_object_prototype()->GetProperty(*key);
4197}
4198
4199
lrn@chromium.org303ada72010-10-27 09:33:13 +00004200static MaybeObject* Runtime_ToFastProperties(Arguments args) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004201 HandleScope scope;
4202
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004203 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004204 Handle<Object> object = args.at<Object>(0);
4205 if (object->IsJSObject()) {
4206 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
ager@chromium.org5c838252010-02-19 08:53:10 +00004207 if (!js_object->HasFastProperties() && !js_object->IsGlobalObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004208 MaybeObject* ok = js_object->TransformToFastProperties(0);
4209 if (ok->IsRetryAfterGC()) return ok;
ager@chromium.org5c838252010-02-19 08:53:10 +00004210 }
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004211 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004212 return *object;
4213}
4214
4215
lrn@chromium.org303ada72010-10-27 09:33:13 +00004216static MaybeObject* Runtime_ToSlowProperties(Arguments args) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004217 HandleScope scope;
4218
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004219 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004220 Handle<Object> object = args.at<Object>(0);
4221 if (object->IsJSObject()) {
4222 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004223 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004224 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004225 return *object;
4226}
4227
4228
lrn@chromium.org303ada72010-10-27 09:33:13 +00004229static MaybeObject* Runtime_ToBool(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004230 NoHandleAllocation ha;
4231 ASSERT(args.length() == 1);
4232
4233 return args[0]->ToBoolean();
4234}
4235
4236
4237// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
4238// Possible optimizations: put the type string into the oddballs.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004239static MaybeObject* Runtime_Typeof(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004240 NoHandleAllocation ha;
4241
4242 Object* obj = args[0];
4243 if (obj->IsNumber()) return Heap::number_symbol();
4244 HeapObject* heap_obj = HeapObject::cast(obj);
4245
4246 // typeof an undetectable object is 'undefined'
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004247 if (heap_obj->map()->is_undetectable()) return Heap::undefined_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004248
4249 InstanceType instance_type = heap_obj->map()->instance_type();
4250 if (instance_type < FIRST_NONSTRING_TYPE) {
4251 return Heap::string_symbol();
4252 }
4253
4254 switch (instance_type) {
4255 case ODDBALL_TYPE:
4256 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
4257 return Heap::boolean_symbol();
4258 }
4259 if (heap_obj->IsNull()) {
4260 return Heap::object_symbol();
4261 }
4262 ASSERT(heap_obj->IsUndefined());
4263 return Heap::undefined_symbol();
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00004264 case JS_FUNCTION_TYPE: case JS_REGEXP_TYPE:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004265 return Heap::function_symbol();
4266 default:
4267 // For any kind of object not handled above, the spec rule for
4268 // host objects gives that it is okay to return "object"
4269 return Heap::object_symbol();
4270 }
4271}
4272
4273
lrn@chromium.org25156de2010-04-06 13:10:27 +00004274static bool AreDigits(const char*s, int from, int to) {
4275 for (int i = from; i < to; i++) {
4276 if (s[i] < '0' || s[i] > '9') return false;
4277 }
4278
4279 return true;
4280}
4281
4282
4283static int ParseDecimalInteger(const char*s, int from, int to) {
4284 ASSERT(to - from < 10); // Overflow is not possible.
4285 ASSERT(from < to);
4286 int d = s[from] - '0';
4287
4288 for (int i = from + 1; i < to; i++) {
4289 d = 10 * d + (s[i] - '0');
4290 }
4291
4292 return d;
4293}
4294
4295
lrn@chromium.org303ada72010-10-27 09:33:13 +00004296static MaybeObject* Runtime_StringToNumber(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004297 NoHandleAllocation ha;
4298 ASSERT(args.length() == 1);
4299 CONVERT_CHECKED(String, subject, args[0]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004300 subject->TryFlatten();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004301
4302 // Fast case: short integer or some sorts of junk values.
4303 int len = subject->length();
4304 if (subject->IsSeqAsciiString()) {
4305 if (len == 0) return Smi::FromInt(0);
4306
4307 char const* data = SeqAsciiString::cast(subject)->GetChars();
4308 bool minus = (data[0] == '-');
4309 int start_pos = (minus ? 1 : 0);
4310
4311 if (start_pos == len) {
4312 return Heap::nan_value();
4313 } else if (data[start_pos] > '9') {
4314 // Fast check for a junk value. A valid string may start from a
4315 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
4316 // the 'I' character ('Infinity'). All of that have codes not greater than
4317 // '9' except 'I'.
4318 if (data[start_pos] != 'I') {
4319 return Heap::nan_value();
4320 }
4321 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
4322 // The maximal/minimal smi has 10 digits. If the string has less digits we
4323 // know it will fit into the smi-data type.
4324 int d = ParseDecimalInteger(data, start_pos, len);
4325 if (minus) {
4326 if (d == 0) return Heap::minus_zero_value();
4327 d = -d;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004328 } else if (!subject->HasHashCode() &&
4329 len <= String::kMaxArrayIndexSize &&
4330 (len == 1 || data[0] != '0')) {
4331 // String hash is not calculated yet but all the data are present.
4332 // Update the hash field to speed up sequential convertions.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00004333 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004334#ifdef DEBUG
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004335 subject->Hash(); // Force hash calculation.
4336 ASSERT_EQ(static_cast<int>(subject->hash_field()),
4337 static_cast<int>(hash));
4338#endif
4339 subject->set_hash_field(hash);
lrn@chromium.org25156de2010-04-06 13:10:27 +00004340 }
4341 return Smi::FromInt(d);
4342 }
4343 }
4344
4345 // Slower case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004346 return Heap::NumberFromDouble(StringToDouble(subject, ALLOW_HEX));
4347}
4348
4349
lrn@chromium.org303ada72010-10-27 09:33:13 +00004350static MaybeObject* Runtime_StringFromCharCodeArray(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004351 NoHandleAllocation ha;
4352 ASSERT(args.length() == 1);
4353
4354 CONVERT_CHECKED(JSArray, codes, args[0]);
4355 int length = Smi::cast(codes->length())->value();
4356
4357 // Check if the string can be ASCII.
4358 int i;
4359 for (i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004360 Object* element;
4361 { MaybeObject* maybe_element = codes->GetElement(i);
4362 // We probably can't get an exception here, but just in order to enforce
4363 // the checking of inputs in the runtime calls we check here.
4364 if (!maybe_element->ToObject(&element)) return maybe_element;
4365 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004366 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
4367 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
4368 break;
4369 }
4370
lrn@chromium.org303ada72010-10-27 09:33:13 +00004371 MaybeObject* maybe_object = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004372 if (i == length) { // The string is ASCII.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004373 maybe_object = Heap::AllocateRawAsciiString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004374 } else { // The string is not ASCII.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004375 maybe_object = Heap::AllocateRawTwoByteString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004376 }
4377
lrn@chromium.org303ada72010-10-27 09:33:13 +00004378 Object* object = NULL;
4379 if (!maybe_object->ToObject(&object)) return maybe_object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004380 String* result = String::cast(object);
4381 for (int i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004382 Object* element;
4383 { MaybeObject* maybe_element = codes->GetElement(i);
4384 if (!maybe_element->ToObject(&element)) return maybe_element;
4385 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004386 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004387 result->Set(i, chr & 0xffff);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004388 }
4389 return result;
4390}
4391
4392
4393// kNotEscaped is generated by the following:
4394//
4395// #!/bin/perl
4396// for (my $i = 0; $i < 256; $i++) {
4397// print "\n" if $i % 16 == 0;
4398// my $c = chr($i);
4399// my $escaped = 1;
4400// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
4401// print $escaped ? "0, " : "1, ";
4402// }
4403
4404
4405static bool IsNotEscaped(uint16_t character) {
4406 // Only for 8 bit characters, the rest are always escaped (in a different way)
4407 ASSERT(character < 256);
4408 static const char kNotEscaped[256] = {
4409 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4410 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4411 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
4412 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
4413 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4414 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
4415 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4416 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
4417 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4418 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4419 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4420 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4421 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4422 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4423 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4424 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4425 };
4426 return kNotEscaped[character] != 0;
4427}
4428
4429
lrn@chromium.org303ada72010-10-27 09:33:13 +00004430static MaybeObject* Runtime_URIEscape(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004431 const char hex_chars[] = "0123456789ABCDEF";
4432 NoHandleAllocation ha;
4433 ASSERT(args.length() == 1);
4434 CONVERT_CHECKED(String, source, args[0]);
4435
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004436 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004437
4438 int escaped_length = 0;
4439 int length = source->length();
4440 {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004441 Access<StringInputBuffer> buffer(&runtime_string_input_buffer);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004442 buffer->Reset(source);
4443 while (buffer->has_more()) {
4444 uint16_t character = buffer->GetNext();
4445 if (character >= 256) {
4446 escaped_length += 6;
4447 } else if (IsNotEscaped(character)) {
4448 escaped_length++;
4449 } else {
4450 escaped_length += 3;
4451 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004452 // We don't allow strings that are longer than a maximal length.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004453 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004454 if (escaped_length > String::kMaxLength) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004455 Top::context()->mark_out_of_memory();
4456 return Failure::OutOfMemoryException();
4457 }
4458 }
4459 }
4460 // No length change implies no change. Return original string if no change.
4461 if (escaped_length == length) {
4462 return source;
4463 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00004464 Object* o;
4465 { MaybeObject* maybe_o = Heap::AllocateRawAsciiString(escaped_length);
4466 if (!maybe_o->ToObject(&o)) return maybe_o;
4467 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004468 String* destination = String::cast(o);
4469 int dest_position = 0;
4470
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004471 Access<StringInputBuffer> buffer(&runtime_string_input_buffer);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004472 buffer->Rewind();
4473 while (buffer->has_more()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00004474 uint16_t chr = buffer->GetNext();
4475 if (chr >= 256) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004476 destination->Set(dest_position, '%');
4477 destination->Set(dest_position+1, 'u');
4478 destination->Set(dest_position+2, hex_chars[chr >> 12]);
4479 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]);
4480 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]);
4481 destination->Set(dest_position+5, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004482 dest_position += 6;
ager@chromium.org870a0b62008-11-04 11:43:05 +00004483 } else if (IsNotEscaped(chr)) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004484 destination->Set(dest_position, chr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004485 dest_position++;
4486 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004487 destination->Set(dest_position, '%');
4488 destination->Set(dest_position+1, hex_chars[chr >> 4]);
4489 destination->Set(dest_position+2, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004490 dest_position += 3;
4491 }
4492 }
4493 return destination;
4494}
4495
4496
4497static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
4498 static const signed char kHexValue['g'] = {
4499 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4500 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4501 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4502 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
4503 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4504 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4505 -1, 10, 11, 12, 13, 14, 15 };
4506
4507 if (character1 > 'f') return -1;
4508 int hi = kHexValue[character1];
4509 if (hi == -1) return -1;
4510 if (character2 > 'f') return -1;
4511 int lo = kHexValue[character2];
4512 if (lo == -1) return -1;
4513 return (hi << 4) + lo;
4514}
4515
4516
ager@chromium.org870a0b62008-11-04 11:43:05 +00004517static inline int Unescape(String* source,
ager@chromium.org870a0b62008-11-04 11:43:05 +00004518 int i,
4519 int length,
4520 int* step) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004521 uint16_t character = source->Get(i);
ager@chromium.org870a0b62008-11-04 11:43:05 +00004522 int32_t hi = 0;
4523 int32_t lo = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004524 if (character == '%' &&
4525 i <= length - 6 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004526 source->Get(i + 1) == 'u' &&
4527 (hi = TwoDigitHex(source->Get(i + 2),
4528 source->Get(i + 3))) != -1 &&
4529 (lo = TwoDigitHex(source->Get(i + 4),
4530 source->Get(i + 5))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004531 *step = 6;
4532 return (hi << 8) + lo;
4533 } else if (character == '%' &&
4534 i <= length - 3 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004535 (lo = TwoDigitHex(source->Get(i + 1),
4536 source->Get(i + 2))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004537 *step = 3;
4538 return lo;
4539 } else {
4540 *step = 1;
4541 return character;
4542 }
4543}
4544
4545
lrn@chromium.org303ada72010-10-27 09:33:13 +00004546static MaybeObject* Runtime_URIUnescape(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004547 NoHandleAllocation ha;
4548 ASSERT(args.length() == 1);
4549 CONVERT_CHECKED(String, source, args[0]);
4550
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004551 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004552
4553 bool ascii = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004554 int length = source->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004555
4556 int unescaped_length = 0;
4557 for (int i = 0; i < length; unescaped_length++) {
4558 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004559 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004560 ascii = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004561 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004562 i += step;
4563 }
4564
4565 // No length change implies no change. Return original string if no change.
4566 if (unescaped_length == length)
4567 return source;
4568
lrn@chromium.org303ada72010-10-27 09:33:13 +00004569 Object* o;
4570 { MaybeObject* maybe_o = ascii ?
4571 Heap::AllocateRawAsciiString(unescaped_length) :
4572 Heap::AllocateRawTwoByteString(unescaped_length);
4573 if (!maybe_o->ToObject(&o)) return maybe_o;
4574 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004575 String* destination = String::cast(o);
4576
4577 int dest_position = 0;
4578 for (int i = 0; i < length; dest_position++) {
4579 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004580 destination->Set(dest_position, Unescape(source, i, length, &step));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004581 i += step;
4582 }
4583 return destination;
4584}
4585
4586
lrn@chromium.org303ada72010-10-27 09:33:13 +00004587static MaybeObject* Runtime_StringParseInt(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004588 NoHandleAllocation ha;
4589
4590 CONVERT_CHECKED(String, s, args[0]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00004591 CONVERT_SMI_CHECKED(radix, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004592
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004593 s->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004594
lrn@chromium.org25156de2010-04-06 13:10:27 +00004595 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
4596 double value = StringToInt(s, radix);
4597 return Heap::NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004598}
4599
4600
lrn@chromium.org303ada72010-10-27 09:33:13 +00004601static MaybeObject* Runtime_StringParseFloat(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004602 NoHandleAllocation ha;
4603 CONVERT_CHECKED(String, str, args[0]);
4604
4605 // ECMA-262 section 15.1.2.3, empty string is NaN
4606 double value = StringToDouble(str, ALLOW_TRAILING_JUNK, OS::nan_value());
4607
4608 // Create a number object from the value.
4609 return Heap::NumberFromDouble(value);
4610}
4611
4612
4613static unibrow::Mapping<unibrow::ToUppercase, 128> to_upper_mapping;
4614static unibrow::Mapping<unibrow::ToLowercase, 128> to_lower_mapping;
4615
4616
4617template <class Converter>
lrn@chromium.org303ada72010-10-27 09:33:13 +00004618MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
4619 String* s,
4620 int length,
4621 int input_string_length,
4622 unibrow::Mapping<Converter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004623 // We try this twice, once with the assumption that the result is no longer
4624 // than the input and, if that assumption breaks, again with the exact
4625 // length. This may not be pretty, but it is nicer than what was here before
4626 // and I hereby claim my vaffel-is.
4627 //
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004628 // Allocate the resulting string.
4629 //
4630 // NOTE: This assumes that the upper/lower case of an ascii
4631 // character is also ascii. This is currently the case, but it
4632 // might break in the future if we implement more context and locale
4633 // dependent upper/lower conversions.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004634 Object* o;
4635 { MaybeObject* maybe_o = s->IsAsciiRepresentation()
4636 ? Heap::AllocateRawAsciiString(length)
4637 : Heap::AllocateRawTwoByteString(length);
4638 if (!maybe_o->ToObject(&o)) return maybe_o;
4639 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004640 String* result = String::cast(o);
4641 bool has_changed_character = false;
4642
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004643 // Convert all characters to upper case, assuming that they will fit
4644 // in the buffer
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004645 Access<StringInputBuffer> buffer(&runtime_string_input_buffer);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004646 buffer->Reset(s);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004647 unibrow::uchar chars[Converter::kMaxWidth];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004648 // We can assume that the string is not empty
4649 uc32 current = buffer->GetNext();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004650 for (int i = 0; i < length;) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00004651 bool has_next = buffer->has_more();
4652 uc32 next = has_next ? buffer->GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004653 int char_length = mapping->get(current, next, chars);
4654 if (char_length == 0) {
4655 // The case conversion of this character is the character itself.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004656 result->Set(i, current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004657 i++;
4658 } else if (char_length == 1) {
4659 // Common case: converting the letter resulted in one character.
4660 ASSERT(static_cast<uc32>(chars[0]) != current);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004661 result->Set(i, chars[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004662 has_changed_character = true;
4663 i++;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004664 } else if (length == input_string_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004665 // We've assumed that the result would be as long as the
4666 // input but here is a character that converts to several
4667 // characters. No matter, we calculate the exact length
4668 // of the result and try the whole thing again.
4669 //
4670 // Note that this leaves room for optimization. We could just
4671 // memcpy what we already have to the result string. Also,
4672 // the result string is the last object allocated we could
4673 // "realloc" it and probably, in the vast majority of cases,
4674 // extend the existing string to be able to hold the full
4675 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00004676 int next_length = 0;
4677 if (has_next) {
4678 next_length = mapping->get(next, 0, chars);
4679 if (next_length == 0) next_length = 1;
4680 }
4681 int current_length = i + char_length + next_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004682 while (buffer->has_more()) {
4683 current = buffer->GetNext();
ager@chromium.org7c537e22008-10-16 08:43:32 +00004684 // NOTE: we use 0 as the next character here because, while
4685 // the next character may affect what a character converts to,
4686 // it does not in any case affect the length of what it convert
4687 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004688 int char_length = mapping->get(current, 0, chars);
4689 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00004690 current_length += char_length;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004691 if (current_length > Smi::kMaxValue) {
4692 Top::context()->mark_out_of_memory();
4693 return Failure::OutOfMemoryException();
4694 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004695 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004696 // Try again with the real length.
4697 return Smi::FromInt(current_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004698 } else {
4699 for (int j = 0; j < char_length; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004700 result->Set(i, chars[j]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004701 i++;
4702 }
4703 has_changed_character = true;
4704 }
4705 current = next;
4706 }
4707 if (has_changed_character) {
4708 return result;
4709 } else {
4710 // If we didn't actually change anything in doing the conversion
4711 // we simple return the result and let the converted string
4712 // become garbage; there is no reason to keep two identical strings
4713 // alive.
4714 return s;
4715 }
4716}
4717
4718
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004719namespace {
4720
lrn@chromium.org303ada72010-10-27 09:33:13 +00004721static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF;
4722
4723
4724// Given a word and two range boundaries returns a word with high bit
4725// set in every byte iff the corresponding input byte was strictly in
4726// the range (m, n). All the other bits in the result are cleared.
4727// This function is only useful when it can be inlined and the
4728// boundaries are statically known.
4729// Requires: all bytes in the input word and the boundaries must be
4730// ascii (less than 0x7F).
4731static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
4732 // Every byte in an ascii string is less than or equal to 0x7F.
4733 ASSERT((w & (kOneInEveryByte * 0x7F)) == w);
4734 // Use strict inequalities since in edge cases the function could be
4735 // further simplified.
4736 ASSERT(0 < m && m < n && n < 0x7F);
4737 // Has high bit set in every w byte less than n.
4738 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w;
4739 // Has high bit set in every w byte greater than m.
4740 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m);
4741 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80));
4742}
4743
4744
4745enum AsciiCaseConversion {
4746 ASCII_TO_LOWER,
4747 ASCII_TO_UPPER
4748};
4749
4750
4751template <AsciiCaseConversion dir>
4752struct FastAsciiConverter {
4753 static bool Convert(char* dst, char* src, int length) {
4754#ifdef DEBUG
4755 char* saved_dst = dst;
4756 char* saved_src = src;
4757#endif
4758 // We rely on the distance between upper and lower case letters
4759 // being a known power of 2.
4760 ASSERT('a' - 'A' == (1 << 5));
4761 // Boundaries for the range of input characters than require conversion.
4762 const char lo = (dir == ASCII_TO_LOWER) ? 'A' - 1 : 'a' - 1;
4763 const char hi = (dir == ASCII_TO_LOWER) ? 'Z' + 1 : 'z' + 1;
4764 bool changed = false;
4765 char* const limit = src + length;
4766#ifdef V8_HOST_CAN_READ_UNALIGNED
4767 // Process the prefix of the input that requires no conversion one
4768 // (machine) word at a time.
4769 while (src <= limit - sizeof(uintptr_t)) {
4770 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
4771 if (AsciiRangeMask(w, lo, hi) != 0) {
4772 changed = true;
4773 break;
4774 }
4775 *reinterpret_cast<uintptr_t*>(dst) = w;
4776 src += sizeof(uintptr_t);
4777 dst += sizeof(uintptr_t);
4778 }
4779 // Process the remainder of the input performing conversion when
4780 // required one word at a time.
4781 while (src <= limit - sizeof(uintptr_t)) {
4782 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
4783 uintptr_t m = AsciiRangeMask(w, lo, hi);
4784 // The mask has high (7th) bit set in every byte that needs
4785 // conversion and we know that the distance between cases is
4786 // 1 << 5.
4787 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
4788 src += sizeof(uintptr_t);
4789 dst += sizeof(uintptr_t);
4790 }
4791#endif
4792 // Process the last few bytes of the input (or the whole input if
4793 // unaligned access is not supported).
4794 while (src < limit) {
4795 char c = *src;
4796 if (lo < c && c < hi) {
4797 c ^= (1 << 5);
4798 changed = true;
4799 }
4800 *dst = c;
4801 ++src;
4802 ++dst;
4803 }
4804#ifdef DEBUG
4805 CheckConvert(saved_dst, saved_src, length, changed);
4806#endif
4807 return changed;
4808 }
4809
4810#ifdef DEBUG
4811 static void CheckConvert(char* dst, char* src, int length, bool changed) {
4812 bool expected_changed = false;
4813 for (int i = 0; i < length; i++) {
4814 if (dst[i] == src[i]) continue;
4815 expected_changed = true;
4816 if (dir == ASCII_TO_LOWER) {
4817 ASSERT('A' <= src[i] && src[i] <= 'Z');
4818 ASSERT(dst[i] == src[i] + ('a' - 'A'));
4819 } else {
4820 ASSERT(dir == ASCII_TO_UPPER);
4821 ASSERT('a' <= src[i] && src[i] <= 'z');
4822 ASSERT(dst[i] == src[i] - ('a' - 'A'));
4823 }
4824 }
4825 ASSERT(expected_changed == changed);
4826 }
4827#endif
4828};
4829
4830
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004831struct ToLowerTraits {
4832 typedef unibrow::ToLowercase UnibrowConverter;
4833
lrn@chromium.org303ada72010-10-27 09:33:13 +00004834 typedef FastAsciiConverter<ASCII_TO_LOWER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004835};
4836
4837
4838struct ToUpperTraits {
4839 typedef unibrow::ToUppercase UnibrowConverter;
4840
lrn@chromium.org303ada72010-10-27 09:33:13 +00004841 typedef FastAsciiConverter<ASCII_TO_UPPER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004842};
4843
4844} // namespace
4845
4846
4847template <typename ConvertTraits>
lrn@chromium.org303ada72010-10-27 09:33:13 +00004848MUST_USE_RESULT static MaybeObject* ConvertCase(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004849 Arguments args,
4850 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004851 NoHandleAllocation ha;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004852 CONVERT_CHECKED(String, s, args[0]);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00004853 s = s->TryFlattenGetString();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004854
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004855 const int length = s->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004856 // Assume that the string is not empty; we need this assumption later
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004857 if (length == 0) return s;
4858
4859 // Simpler handling of ascii strings.
4860 //
4861 // NOTE: This assumes that the upper/lower case of an ascii
4862 // character is also ascii. This is currently the case, but it
4863 // might break in the future if we implement more context and locale
4864 // dependent upper/lower conversions.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00004865 if (s->IsSeqAsciiString()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004866 Object* o;
4867 { MaybeObject* maybe_o = Heap::AllocateRawAsciiString(length);
4868 if (!maybe_o->ToObject(&o)) return maybe_o;
4869 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004870 SeqAsciiString* result = SeqAsciiString::cast(o);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004871 bool has_changed_character = ConvertTraits::AsciiConverter::Convert(
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00004872 result->GetChars(), SeqAsciiString::cast(s)->GetChars(), length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004873 return has_changed_character ? result : s;
4874 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004875
lrn@chromium.org303ada72010-10-27 09:33:13 +00004876 Object* answer;
4877 { MaybeObject* maybe_answer = ConvertCaseHelper(s, length, length, mapping);
4878 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
4879 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004880 if (answer->IsSmi()) {
4881 // Retry with correct length.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004882 { MaybeObject* maybe_answer =
4883 ConvertCaseHelper(s, Smi::cast(answer)->value(), length, mapping);
4884 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
4885 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004886 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00004887 return answer;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004888}
4889
4890
lrn@chromium.org303ada72010-10-27 09:33:13 +00004891static MaybeObject* Runtime_StringToLowerCase(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004892 return ConvertCase<ToLowerTraits>(args, &to_lower_mapping);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004893}
4894
4895
lrn@chromium.org303ada72010-10-27 09:33:13 +00004896static MaybeObject* Runtime_StringToUpperCase(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004897 return ConvertCase<ToUpperTraits>(args, &to_upper_mapping);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004898}
4899
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004900
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004901static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
4902 return unibrow::WhiteSpace::Is(c) || c == 0x200b;
4903}
4904
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004905
lrn@chromium.org303ada72010-10-27 09:33:13 +00004906static MaybeObject* Runtime_StringTrim(Arguments args) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004907 NoHandleAllocation ha;
4908 ASSERT(args.length() == 3);
4909
4910 CONVERT_CHECKED(String, s, args[0]);
4911 CONVERT_BOOLEAN_CHECKED(trimLeft, args[1]);
4912 CONVERT_BOOLEAN_CHECKED(trimRight, args[2]);
4913
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004914 s->TryFlatten();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004915 int length = s->length();
4916
4917 int left = 0;
4918 if (trimLeft) {
4919 while (left < length && IsTrimWhiteSpace(s->Get(left))) {
4920 left++;
4921 }
4922 }
4923
4924 int right = length;
4925 if (trimRight) {
4926 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) {
4927 right--;
4928 }
4929 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00004930 return s->SubString(left, right);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004931}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004932
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004933
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00004934template <typename SubjectChar, typename PatternChar>
4935void FindStringIndices(Vector<const SubjectChar> subject,
4936 Vector<const PatternChar> pattern,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00004937 ZoneList<int>* indices,
4938 unsigned int limit) {
4939 ASSERT(limit > 0);
4940 // Collect indices of pattern in subject, and the end-of-string index.
4941 // Stop after finding at most limit values.
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00004942 StringSearch<PatternChar, SubjectChar> search(pattern);
4943 int pattern_length = pattern.length();
4944 int index = 0;
4945 while (limit > 0) {
4946 index = search.Search(subject, index);
4947 if (index < 0) return;
4948 indices->Add(index);
4949 index += pattern_length;
4950 limit--;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00004951 }
4952}
4953
fschneider@chromium.org086aac62010-03-17 13:18:24 +00004954
lrn@chromium.org303ada72010-10-27 09:33:13 +00004955static MaybeObject* Runtime_StringSplit(Arguments args) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00004956 ASSERT(args.length() == 3);
4957 HandleScope handle_scope;
4958 CONVERT_ARG_CHECKED(String, subject, 0);
4959 CONVERT_ARG_CHECKED(String, pattern, 1);
4960 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
4961
4962 int subject_length = subject->length();
4963 int pattern_length = pattern->length();
4964 RUNTIME_ASSERT(pattern_length > 0);
4965
4966 // The limit can be very large (0xffffffffu), but since the pattern
4967 // isn't empty, we can never create more parts than ~half the length
4968 // of the subject.
4969
4970 if (!subject->IsFlat()) FlattenString(subject);
4971
4972 static const int kMaxInitialListCapacity = 16;
4973
4974 ZoneScope scope(DELETE_ON_EXIT);
4975
4976 // Find (up to limit) indices of separator and end-of-string in subject
4977 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
4978 ZoneList<int> indices(initial_capacity);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004979 if (!pattern->IsFlat()) FlattenString(pattern);
4980
4981 // No allocation block.
4982 {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00004983 AssertNoAllocation nogc;
4984 if (subject->IsAsciiRepresentation()) {
4985 Vector<const char> subject_vector = subject->ToAsciiVector();
4986 if (pattern->IsAsciiRepresentation()) {
4987 FindStringIndices(subject_vector,
4988 pattern->ToAsciiVector(),
4989 &indices,
4990 limit);
4991 } else {
4992 FindStringIndices(subject_vector,
4993 pattern->ToUC16Vector(),
4994 &indices,
4995 limit);
4996 }
4997 } else {
4998 Vector<const uc16> subject_vector = subject->ToUC16Vector();
4999 if (pattern->IsAsciiRepresentation()) {
5000 FindStringIndices(subject_vector,
5001 pattern->ToAsciiVector(),
5002 &indices,
5003 limit);
5004 } else {
5005 FindStringIndices(subject_vector,
5006 pattern->ToUC16Vector(),
5007 &indices,
5008 limit);
5009 }
5010 }
5011 }
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005012
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005013 if (static_cast<uint32_t>(indices.length()) < limit) {
5014 indices.Add(subject_length);
5015 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005016
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005017 // The list indices now contains the end of each part to create.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005018
5019 // Create JSArray of substrings separated by separator.
5020 int part_count = indices.length();
5021
5022 Handle<JSArray> result = Factory::NewJSArray(part_count);
5023 result->set_length(Smi::FromInt(part_count));
5024
5025 ASSERT(result->HasFastElements());
5026
5027 if (part_count == 1 && indices.at(0) == subject_length) {
5028 FixedArray::cast(result->elements())->set(0, *subject);
5029 return *result;
5030 }
5031
5032 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
5033 int part_start = 0;
5034 for (int i = 0; i < part_count; i++) {
5035 HandleScope local_loop_handle;
5036 int part_end = indices.at(i);
5037 Handle<String> substring =
5038 Factory::NewSubString(subject, part_start, part_end);
5039 elements->set(i, *substring);
5040 part_start = part_end + pattern_length;
5041 }
5042
5043 return *result;
5044}
5045
5046
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005047// Copies ascii characters to the given fixed array looking up
5048// one-char strings in the cache. Gives up on the first char that is
5049// not in the cache and fills the remainder with smi zeros. Returns
5050// the length of the successfully copied prefix.
5051static int CopyCachedAsciiCharsToArray(const char* chars,
5052 FixedArray* elements,
5053 int length) {
5054 AssertNoAllocation nogc;
5055 FixedArray* ascii_cache = Heap::single_character_string_cache();
5056 Object* undefined = Heap::undefined_value();
5057 int i;
5058 for (i = 0; i < length; ++i) {
5059 Object* value = ascii_cache->get(chars[i]);
5060 if (value == undefined) break;
5061 ASSERT(!Heap::InNewSpace(value));
5062 elements->set(i, value, SKIP_WRITE_BARRIER);
5063 }
5064 if (i < length) {
5065 ASSERT(Smi::FromInt(0) == 0);
5066 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
5067 }
5068#ifdef DEBUG
5069 for (int j = 0; j < length; ++j) {
5070 Object* element = elements->get(j);
5071 ASSERT(element == Smi::FromInt(0) ||
5072 (element->IsString() && String::cast(element)->LooksValid()));
5073 }
5074#endif
5075 return i;
5076}
5077
5078
5079// Converts a String to JSArray.
5080// For example, "foo" => ["f", "o", "o"].
lrn@chromium.org303ada72010-10-27 09:33:13 +00005081static MaybeObject* Runtime_StringToArray(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005082 HandleScope scope;
5083 ASSERT(args.length() == 1);
5084 CONVERT_ARG_CHECKED(String, s, 0);
5085
5086 s->TryFlatten();
5087 const int length = s->length();
5088
5089 Handle<FixedArray> elements;
5090 if (s->IsFlat() && s->IsAsciiRepresentation()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005091 Object* obj;
5092 { MaybeObject* maybe_obj = Heap::AllocateUninitializedFixedArray(length);
5093 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5094 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005095 elements = Handle<FixedArray>(FixedArray::cast(obj));
5096
5097 Vector<const char> chars = s->ToAsciiVector();
5098 // Note, this will initialize all elements (not only the prefix)
5099 // to prevent GC from seeing partially initialized array.
5100 int num_copied_from_cache = CopyCachedAsciiCharsToArray(chars.start(),
5101 *elements,
5102 length);
5103
5104 for (int i = num_copied_from_cache; i < length; ++i) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00005105 Handle<Object> str = LookupSingleCharacterStringFromCode(chars[i]);
5106 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005107 }
5108 } else {
5109 elements = Factory::NewFixedArray(length);
5110 for (int i = 0; i < length; ++i) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00005111 Handle<Object> str = LookupSingleCharacterStringFromCode(s->Get(i));
5112 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005113 }
5114 }
5115
5116#ifdef DEBUG
5117 for (int i = 0; i < length; ++i) {
5118 ASSERT(String::cast(elements->get(i))->length() == 1);
5119 }
5120#endif
5121
5122 return *Factory::NewJSArrayWithElements(elements);
5123}
5124
5125
lrn@chromium.org303ada72010-10-27 09:33:13 +00005126static MaybeObject* Runtime_NewStringWrapper(Arguments args) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005127 NoHandleAllocation ha;
5128 ASSERT(args.length() == 1);
5129 CONVERT_CHECKED(String, value, args[0]);
5130 return value->ToObject();
5131}
5132
5133
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00005134bool Runtime::IsUpperCaseChar(uint16_t ch) {
5135 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
5136 int char_length = to_upper_mapping.get(ch, 0, chars);
5137 return char_length == 0;
5138}
5139
5140
lrn@chromium.org303ada72010-10-27 09:33:13 +00005141static MaybeObject* Runtime_NumberToString(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005142 NoHandleAllocation ha;
5143 ASSERT(args.length() == 1);
5144
5145 Object* number = args[0];
5146 RUNTIME_ASSERT(number->IsNumber());
5147
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005148 return Heap::NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005149}
5150
5151
lrn@chromium.org303ada72010-10-27 09:33:13 +00005152static MaybeObject* Runtime_NumberToStringSkipCache(Arguments args) {
ager@chromium.org357bf652010-04-12 11:30:10 +00005153 NoHandleAllocation ha;
5154 ASSERT(args.length() == 1);
5155
5156 Object* number = args[0];
5157 RUNTIME_ASSERT(number->IsNumber());
5158
5159 return Heap::NumberToString(number, false);
5160}
5161
5162
lrn@chromium.org303ada72010-10-27 09:33:13 +00005163static MaybeObject* Runtime_NumberToInteger(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005164 NoHandleAllocation ha;
5165 ASSERT(args.length() == 1);
5166
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005167 CONVERT_DOUBLE_CHECKED(number, args[0]);
5168
5169 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5170 if (number > 0 && number <= Smi::kMaxValue) {
5171 return Smi::FromInt(static_cast<int>(number));
5172 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005173 return Heap::NumberFromDouble(DoubleToInteger(number));
5174}
5175
5176
lrn@chromium.org303ada72010-10-27 09:33:13 +00005177static MaybeObject* Runtime_NumberToIntegerMapMinusZero(Arguments args) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005178 NoHandleAllocation ha;
5179 ASSERT(args.length() == 1);
5180
5181 CONVERT_DOUBLE_CHECKED(number, args[0]);
5182
5183 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5184 if (number > 0 && number <= Smi::kMaxValue) {
5185 return Smi::FromInt(static_cast<int>(number));
5186 }
5187
5188 double double_value = DoubleToInteger(number);
5189 // Map both -0 and +0 to +0.
5190 if (double_value == 0) double_value = 0;
5191
5192 return Heap::NumberFromDouble(double_value);
5193}
5194
5195
lrn@chromium.org303ada72010-10-27 09:33:13 +00005196static MaybeObject* Runtime_NumberToJSUint32(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005197 NoHandleAllocation ha;
5198 ASSERT(args.length() == 1);
5199
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005200 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005201 return Heap::NumberFromUint32(number);
5202}
5203
5204
lrn@chromium.org303ada72010-10-27 09:33:13 +00005205static MaybeObject* Runtime_NumberToJSInt32(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005206 NoHandleAllocation ha;
5207 ASSERT(args.length() == 1);
5208
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005209 CONVERT_DOUBLE_CHECKED(number, args[0]);
5210
5211 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5212 if (number > 0 && number <= Smi::kMaxValue) {
5213 return Smi::FromInt(static_cast<int>(number));
5214 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005215 return Heap::NumberFromInt32(DoubleToInt32(number));
5216}
5217
5218
ager@chromium.org870a0b62008-11-04 11:43:05 +00005219// Converts a Number to a Smi, if possible. Returns NaN if the number is not
5220// a small integer.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005221static MaybeObject* Runtime_NumberToSmi(Arguments args) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00005222 NoHandleAllocation ha;
5223 ASSERT(args.length() == 1);
5224
5225 Object* obj = args[0];
5226 if (obj->IsSmi()) {
5227 return obj;
5228 }
5229 if (obj->IsHeapNumber()) {
5230 double value = HeapNumber::cast(obj)->value();
5231 int int_value = FastD2I(value);
5232 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
5233 return Smi::FromInt(int_value);
5234 }
5235 }
5236 return Heap::nan_value();
5237}
5238
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005239
lrn@chromium.org303ada72010-10-27 09:33:13 +00005240static MaybeObject* Runtime_NumberAdd(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005241 NoHandleAllocation ha;
5242 ASSERT(args.length() == 2);
5243
5244 CONVERT_DOUBLE_CHECKED(x, args[0]);
5245 CONVERT_DOUBLE_CHECKED(y, args[1]);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00005246 return Heap::NumberFromDouble(x + y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005247}
5248
5249
lrn@chromium.org303ada72010-10-27 09:33:13 +00005250static MaybeObject* Runtime_NumberSub(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005251 NoHandleAllocation ha;
5252 ASSERT(args.length() == 2);
5253
5254 CONVERT_DOUBLE_CHECKED(x, args[0]);
5255 CONVERT_DOUBLE_CHECKED(y, args[1]);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00005256 return Heap::NumberFromDouble(x - y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005257}
5258
5259
lrn@chromium.org303ada72010-10-27 09:33:13 +00005260static MaybeObject* Runtime_NumberMul(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005261 NoHandleAllocation ha;
5262 ASSERT(args.length() == 2);
5263
5264 CONVERT_DOUBLE_CHECKED(x, args[0]);
5265 CONVERT_DOUBLE_CHECKED(y, args[1]);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00005266 return Heap::NumberFromDouble(x * y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005267}
5268
5269
lrn@chromium.org303ada72010-10-27 09:33:13 +00005270static MaybeObject* Runtime_NumberUnaryMinus(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005271 NoHandleAllocation ha;
5272 ASSERT(args.length() == 1);
5273
5274 CONVERT_DOUBLE_CHECKED(x, args[0]);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00005275 return Heap::NumberFromDouble(-x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005276}
5277
5278
lrn@chromium.org303ada72010-10-27 09:33:13 +00005279static MaybeObject* Runtime_NumberAlloc(Arguments args) {
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00005280 NoHandleAllocation ha;
5281 ASSERT(args.length() == 0);
5282
5283 return Heap::NumberFromDouble(9876543210.0);
5284}
5285
5286
lrn@chromium.org303ada72010-10-27 09:33:13 +00005287static MaybeObject* Runtime_NumberDiv(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005288 NoHandleAllocation ha;
5289 ASSERT(args.length() == 2);
5290
5291 CONVERT_DOUBLE_CHECKED(x, args[0]);
5292 CONVERT_DOUBLE_CHECKED(y, args[1]);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00005293 return Heap::NumberFromDouble(x / y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005294}
5295
5296
lrn@chromium.org303ada72010-10-27 09:33:13 +00005297static MaybeObject* Runtime_NumberMod(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005298 NoHandleAllocation ha;
5299 ASSERT(args.length() == 2);
5300
5301 CONVERT_DOUBLE_CHECKED(x, args[0]);
5302 CONVERT_DOUBLE_CHECKED(y, args[1]);
5303
ager@chromium.org3811b432009-10-28 14:53:37 +00005304 x = modulo(x, y);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00005305 // NumberFromDouble may return a Smi instead of a Number object
5306 return Heap::NumberFromDouble(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005307}
5308
5309
lrn@chromium.org303ada72010-10-27 09:33:13 +00005310static MaybeObject* Runtime_StringAdd(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005311 NoHandleAllocation ha;
5312 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005313 CONVERT_CHECKED(String, str1, args[0]);
5314 CONVERT_CHECKED(String, str2, args[1]);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00005315 Counters::string_add_runtime.Increment();
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00005316 return Heap::AllocateConsString(str1, str2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005317}
5318
5319
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005320template <typename sinkchar>
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005321static inline void StringBuilderConcatHelper(String* special,
5322 sinkchar* sink,
5323 FixedArray* fixed_array,
5324 int array_length) {
5325 int position = 0;
5326 for (int i = 0; i < array_length; i++) {
5327 Object* element = fixed_array->get(i);
5328 if (element->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005329 // Smi encoding of position and length.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005330 int encoded_slice = Smi::cast(element)->value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005331 int pos;
5332 int len;
5333 if (encoded_slice > 0) {
5334 // Position and length encoded in one smi.
5335 pos = StringBuilderSubstringPosition::decode(encoded_slice);
5336 len = StringBuilderSubstringLength::decode(encoded_slice);
5337 } else {
5338 // Position and length encoded in two smis.
5339 Object* obj = fixed_array->get(++i);
5340 ASSERT(obj->IsSmi());
5341 pos = Smi::cast(obj)->value();
5342 len = -encoded_slice;
5343 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00005344 String::WriteToFlat(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00005345 sink + position,
5346 pos,
5347 pos + len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005348 position += len;
5349 } else {
5350 String* string = String::cast(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005351 int element_length = string->length();
5352 String::WriteToFlat(string, sink + position, 0, element_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005353 position += element_length;
5354 }
5355 }
5356}
5357
5358
lrn@chromium.org303ada72010-10-27 09:33:13 +00005359static MaybeObject* Runtime_StringBuilderConcat(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005360 NoHandleAllocation ha;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005361 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005362 CONVERT_CHECKED(JSArray, array, args[0]);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005363 if (!args[1]->IsSmi()) {
5364 Top::context()->mark_out_of_memory();
5365 return Failure::OutOfMemoryException();
5366 }
5367 int array_length = Smi::cast(args[1])->value();
5368 CONVERT_CHECKED(String, special, args[2]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005369
5370 // This assumption is used by the slice encoding in one or two smis.
5371 ASSERT(Smi::kMaxValue >= String::kMaxLength);
5372
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005373 int special_length = special->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005374 if (!array->HasFastElements()) {
5375 return Top::Throw(Heap::illegal_argument_symbol());
5376 }
5377 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005378 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005379 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005380 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005381
5382 if (array_length == 0) {
5383 return Heap::empty_string();
5384 } else if (array_length == 1) {
5385 Object* first = fixed_array->get(0);
5386 if (first->IsString()) return first;
5387 }
5388
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005389 bool ascii = special->HasOnlyAsciiChars();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005390 int position = 0;
5391 for (int i = 0; i < array_length; i++) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005392 int increment = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005393 Object* elt = fixed_array->get(i);
5394 if (elt->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005395 // Smi encoding of position and length.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005396 int smi_value = Smi::cast(elt)->value();
5397 int pos;
5398 int len;
5399 if (smi_value > 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005400 // Position and length encoded in one smi.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005401 pos = StringBuilderSubstringPosition::decode(smi_value);
5402 len = StringBuilderSubstringLength::decode(smi_value);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005403 } else {
5404 // Position and length encoded in two smis.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005405 len = -smi_value;
5406 // Get the position and check that it is a positive smi.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005407 i++;
5408 if (i >= array_length) {
5409 return Top::Throw(Heap::illegal_argument_symbol());
5410 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005411 Object* next_smi = fixed_array->get(i);
5412 if (!next_smi->IsSmi()) {
5413 return Top::Throw(Heap::illegal_argument_symbol());
5414 }
5415 pos = Smi::cast(next_smi)->value();
5416 if (pos < 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005417 return Top::Throw(Heap::illegal_argument_symbol());
5418 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005419 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005420 ASSERT(pos >= 0);
5421 ASSERT(len >= 0);
5422 if (pos > special_length || len > special_length - pos) {
5423 return Top::Throw(Heap::illegal_argument_symbol());
5424 }
5425 increment = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005426 } else if (elt->IsString()) {
5427 String* element = String::cast(elt);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005428 int element_length = element->length();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005429 increment = element_length;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005430 if (ascii && !element->HasOnlyAsciiChars()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005431 ascii = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005432 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005433 } else {
5434 return Top::Throw(Heap::illegal_argument_symbol());
5435 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005436 if (increment > String::kMaxLength - position) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005437 Top::context()->mark_out_of_memory();
5438 return Failure::OutOfMemoryException();
5439 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005440 position += increment;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005441 }
5442
5443 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005444 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005445
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005446 if (ascii) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005447 { MaybeObject* maybe_object = Heap::AllocateRawAsciiString(length);
5448 if (!maybe_object->ToObject(&object)) return maybe_object;
5449 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005450 SeqAsciiString* answer = SeqAsciiString::cast(object);
5451 StringBuilderConcatHelper(special,
5452 answer->GetChars(),
5453 fixed_array,
5454 array_length);
5455 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005456 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005457 { MaybeObject* maybe_object = Heap::AllocateRawTwoByteString(length);
5458 if (!maybe_object->ToObject(&object)) return maybe_object;
5459 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005460 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
5461 StringBuilderConcatHelper(special,
5462 answer->GetChars(),
5463 fixed_array,
5464 array_length);
5465 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005466 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005467}
5468
5469
lrn@chromium.org303ada72010-10-27 09:33:13 +00005470static MaybeObject* Runtime_NumberOr(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005471 NoHandleAllocation ha;
5472 ASSERT(args.length() == 2);
5473
5474 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5475 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5476 return Heap::NumberFromInt32(x | y);
5477}
5478
5479
lrn@chromium.org303ada72010-10-27 09:33:13 +00005480static MaybeObject* Runtime_NumberAnd(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005481 NoHandleAllocation ha;
5482 ASSERT(args.length() == 2);
5483
5484 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5485 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5486 return Heap::NumberFromInt32(x & y);
5487}
5488
5489
lrn@chromium.org303ada72010-10-27 09:33:13 +00005490static MaybeObject* Runtime_NumberXor(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005491 NoHandleAllocation ha;
5492 ASSERT(args.length() == 2);
5493
5494 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5495 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5496 return Heap::NumberFromInt32(x ^ y);
5497}
5498
5499
lrn@chromium.org303ada72010-10-27 09:33:13 +00005500static MaybeObject* Runtime_NumberNot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005501 NoHandleAllocation ha;
5502 ASSERT(args.length() == 1);
5503
5504 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5505 return Heap::NumberFromInt32(~x);
5506}
5507
5508
lrn@chromium.org303ada72010-10-27 09:33:13 +00005509static MaybeObject* Runtime_NumberShl(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005510 NoHandleAllocation ha;
5511 ASSERT(args.length() == 2);
5512
5513 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5514 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5515 return Heap::NumberFromInt32(x << (y & 0x1f));
5516}
5517
5518
lrn@chromium.org303ada72010-10-27 09:33:13 +00005519static MaybeObject* Runtime_NumberShr(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005520 NoHandleAllocation ha;
5521 ASSERT(args.length() == 2);
5522
5523 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
5524 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5525 return Heap::NumberFromUint32(x >> (y & 0x1f));
5526}
5527
5528
lrn@chromium.org303ada72010-10-27 09:33:13 +00005529static MaybeObject* Runtime_NumberSar(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005530 NoHandleAllocation ha;
5531 ASSERT(args.length() == 2);
5532
5533 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5534 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5535 return Heap::NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
5536}
5537
5538
lrn@chromium.org303ada72010-10-27 09:33:13 +00005539static MaybeObject* Runtime_NumberEquals(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005540 NoHandleAllocation ha;
5541 ASSERT(args.length() == 2);
5542
5543 CONVERT_DOUBLE_CHECKED(x, args[0]);
5544 CONVERT_DOUBLE_CHECKED(y, args[1]);
5545 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
5546 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
5547 if (x == y) return Smi::FromInt(EQUAL);
5548 Object* result;
5549 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
5550 result = Smi::FromInt(EQUAL);
5551 } else {
5552 result = Smi::FromInt(NOT_EQUAL);
5553 }
5554 return result;
5555}
5556
5557
lrn@chromium.org303ada72010-10-27 09:33:13 +00005558static MaybeObject* Runtime_StringEquals(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005559 NoHandleAllocation ha;
5560 ASSERT(args.length() == 2);
5561
5562 CONVERT_CHECKED(String, x, args[0]);
5563 CONVERT_CHECKED(String, y, args[1]);
5564
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005565 bool not_equal = !x->Equals(y);
5566 // This is slightly convoluted because the value that signifies
5567 // equality is 0 and inequality is 1 so we have to negate the result
5568 // from String::Equals.
5569 ASSERT(not_equal == 0 || not_equal == 1);
5570 STATIC_CHECK(EQUAL == 0);
5571 STATIC_CHECK(NOT_EQUAL == 1);
5572 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005573}
5574
5575
lrn@chromium.org303ada72010-10-27 09:33:13 +00005576static MaybeObject* Runtime_NumberCompare(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005577 NoHandleAllocation ha;
5578 ASSERT(args.length() == 3);
5579
5580 CONVERT_DOUBLE_CHECKED(x, args[0]);
5581 CONVERT_DOUBLE_CHECKED(y, args[1]);
5582 if (isnan(x) || isnan(y)) return args[2];
5583 if (x == y) return Smi::FromInt(EQUAL);
5584 if (isless(x, y)) return Smi::FromInt(LESS);
5585 return Smi::FromInt(GREATER);
5586}
5587
5588
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005589// Compare two Smis as if they were converted to strings and then
5590// compared lexicographically.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005591static MaybeObject* Runtime_SmiLexicographicCompare(Arguments args) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005592 NoHandleAllocation ha;
5593 ASSERT(args.length() == 2);
5594
5595 // Arrays for the individual characters of the two Smis. Smis are
5596 // 31 bit integers and 10 decimal digits are therefore enough.
5597 static int x_elms[10];
5598 static int y_elms[10];
5599
5600 // Extract the integer values from the Smis.
5601 CONVERT_CHECKED(Smi, x, args[0]);
5602 CONVERT_CHECKED(Smi, y, args[1]);
5603 int x_value = x->value();
5604 int y_value = y->value();
5605
5606 // If the integers are equal so are the string representations.
5607 if (x_value == y_value) return Smi::FromInt(EQUAL);
5608
5609 // If one of the integers are zero the normal integer order is the
5610 // same as the lexicographic order of the string representations.
5611 if (x_value == 0 || y_value == 0) return Smi::FromInt(x_value - y_value);
5612
ager@chromium.org32912102009-01-16 10:38:43 +00005613 // If only one of the integers is negative the negative number is
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005614 // smallest because the char code of '-' is less than the char code
5615 // of any digit. Otherwise, we make both values positive.
5616 if (x_value < 0 || y_value < 0) {
5617 if (y_value >= 0) return Smi::FromInt(LESS);
5618 if (x_value >= 0) return Smi::FromInt(GREATER);
5619 x_value = -x_value;
5620 y_value = -y_value;
5621 }
5622
5623 // Convert the integers to arrays of their decimal digits.
5624 int x_index = 0;
5625 int y_index = 0;
5626 while (x_value > 0) {
5627 x_elms[x_index++] = x_value % 10;
5628 x_value /= 10;
5629 }
5630 while (y_value > 0) {
5631 y_elms[y_index++] = y_value % 10;
5632 y_value /= 10;
5633 }
5634
5635 // Loop through the arrays of decimal digits finding the first place
5636 // where they differ.
5637 while (--x_index >= 0 && --y_index >= 0) {
5638 int diff = x_elms[x_index] - y_elms[y_index];
5639 if (diff != 0) return Smi::FromInt(diff);
5640 }
5641
5642 // If one array is a suffix of the other array, the longest array is
5643 // the representation of the largest of the Smis in the
5644 // lexicographic ordering.
5645 return Smi::FromInt(x_index - y_index);
5646}
5647
5648
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005649static Object* StringInputBufferCompare(String* x, String* y) {
5650 static StringInputBuffer bufx;
5651 static StringInputBuffer bufy;
5652 bufx.Reset(x);
5653 bufy.Reset(y);
5654 while (bufx.has_more() && bufy.has_more()) {
5655 int d = bufx.GetNext() - bufy.GetNext();
5656 if (d < 0) return Smi::FromInt(LESS);
5657 else if (d > 0) return Smi::FromInt(GREATER);
5658 }
5659
5660 // x is (non-trivial) prefix of y:
5661 if (bufy.has_more()) return Smi::FromInt(LESS);
5662 // y is prefix of x:
5663 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
5664}
5665
5666
5667static Object* FlatStringCompare(String* x, String* y) {
5668 ASSERT(x->IsFlat());
5669 ASSERT(y->IsFlat());
5670 Object* equal_prefix_result = Smi::FromInt(EQUAL);
5671 int prefix_length = x->length();
5672 if (y->length() < prefix_length) {
5673 prefix_length = y->length();
5674 equal_prefix_result = Smi::FromInt(GREATER);
5675 } else if (y->length() > prefix_length) {
5676 equal_prefix_result = Smi::FromInt(LESS);
5677 }
5678 int r;
5679 if (x->IsAsciiRepresentation()) {
5680 Vector<const char> x_chars = x->ToAsciiVector();
5681 if (y->IsAsciiRepresentation()) {
5682 Vector<const char> y_chars = y->ToAsciiVector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005683 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005684 } else {
5685 Vector<const uc16> y_chars = y->ToUC16Vector();
5686 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
5687 }
5688 } else {
5689 Vector<const uc16> x_chars = x->ToUC16Vector();
5690 if (y->IsAsciiRepresentation()) {
5691 Vector<const char> y_chars = y->ToAsciiVector();
5692 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
5693 } else {
5694 Vector<const uc16> y_chars = y->ToUC16Vector();
5695 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
5696 }
5697 }
5698 Object* result;
5699 if (r == 0) {
5700 result = equal_prefix_result;
5701 } else {
5702 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
5703 }
5704 ASSERT(result == StringInputBufferCompare(x, y));
5705 return result;
5706}
5707
5708
lrn@chromium.org303ada72010-10-27 09:33:13 +00005709static MaybeObject* Runtime_StringCompare(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005710 NoHandleAllocation ha;
5711 ASSERT(args.length() == 2);
5712
5713 CONVERT_CHECKED(String, x, args[0]);
5714 CONVERT_CHECKED(String, y, args[1]);
5715
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005716 Counters::string_compare_runtime.Increment();
5717
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005718 // A few fast case tests before we flatten.
5719 if (x == y) return Smi::FromInt(EQUAL);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005720 if (y->length() == 0) {
5721 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005722 return Smi::FromInt(GREATER);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005723 } else if (x->length() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005724 return Smi::FromInt(LESS);
5725 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005726
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005727 int d = x->Get(0) - y->Get(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005728 if (d < 0) return Smi::FromInt(LESS);
5729 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005730
lrn@chromium.org303ada72010-10-27 09:33:13 +00005731 Object* obj;
5732 { MaybeObject* maybe_obj = Heap::PrepareForCompare(x);
5733 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5734 }
5735 { MaybeObject* maybe_obj = Heap::PrepareForCompare(y);
5736 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5737 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005738
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005739 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
5740 : StringInputBufferCompare(x, y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005741}
5742
5743
lrn@chromium.org303ada72010-10-27 09:33:13 +00005744static MaybeObject* Runtime_Math_acos(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005745 NoHandleAllocation ha;
5746 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005747 Counters::math_acos.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005748
5749 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005750 return TranscendentalCache::Get(TranscendentalCache::ACOS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005751}
5752
5753
lrn@chromium.org303ada72010-10-27 09:33:13 +00005754static MaybeObject* Runtime_Math_asin(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005755 NoHandleAllocation ha;
5756 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005757 Counters::math_asin.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005758
5759 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005760 return TranscendentalCache::Get(TranscendentalCache::ASIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005761}
5762
5763
lrn@chromium.org303ada72010-10-27 09:33:13 +00005764static MaybeObject* Runtime_Math_atan(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005765 NoHandleAllocation ha;
5766 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005767 Counters::math_atan.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005768
5769 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005770 return TranscendentalCache::Get(TranscendentalCache::ATAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005771}
5772
5773
lrn@chromium.org303ada72010-10-27 09:33:13 +00005774static MaybeObject* Runtime_Math_atan2(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005775 NoHandleAllocation ha;
5776 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005777 Counters::math_atan2.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005778
5779 CONVERT_DOUBLE_CHECKED(x, args[0]);
5780 CONVERT_DOUBLE_CHECKED(y, args[1]);
5781 double result;
5782 if (isinf(x) && isinf(y)) {
5783 // Make sure that the result in case of two infinite arguments
5784 // is a multiple of Pi / 4. The sign of the result is determined
5785 // by the first argument (x) and the sign of the second argument
5786 // determines the multiplier: one or three.
5787 static double kPiDividedBy4 = 0.78539816339744830962;
5788 int multiplier = (x < 0) ? -1 : 1;
5789 if (y < 0) multiplier *= 3;
5790 result = multiplier * kPiDividedBy4;
5791 } else {
5792 result = atan2(x, y);
5793 }
5794 return Heap::AllocateHeapNumber(result);
5795}
5796
5797
lrn@chromium.org303ada72010-10-27 09:33:13 +00005798static MaybeObject* Runtime_Math_ceil(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005799 NoHandleAllocation ha;
5800 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005801 Counters::math_ceil.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005802
5803 CONVERT_DOUBLE_CHECKED(x, args[0]);
5804 return Heap::NumberFromDouble(ceiling(x));
5805}
5806
5807
lrn@chromium.org303ada72010-10-27 09:33:13 +00005808static MaybeObject* Runtime_Math_cos(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005809 NoHandleAllocation ha;
5810 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005811 Counters::math_cos.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005812
5813 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005814 return TranscendentalCache::Get(TranscendentalCache::COS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005815}
5816
5817
lrn@chromium.org303ada72010-10-27 09:33:13 +00005818static MaybeObject* Runtime_Math_exp(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005819 NoHandleAllocation ha;
5820 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005821 Counters::math_exp.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005822
5823 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005824 return TranscendentalCache::Get(TranscendentalCache::EXP, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005825}
5826
5827
lrn@chromium.org303ada72010-10-27 09:33:13 +00005828static MaybeObject* Runtime_Math_floor(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005829 NoHandleAllocation ha;
5830 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005831 Counters::math_floor.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005832
5833 CONVERT_DOUBLE_CHECKED(x, args[0]);
5834 return Heap::NumberFromDouble(floor(x));
5835}
5836
5837
lrn@chromium.org303ada72010-10-27 09:33:13 +00005838static MaybeObject* Runtime_Math_log(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005839 NoHandleAllocation ha;
5840 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005841 Counters::math_log.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005842
5843 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005844 return TranscendentalCache::Get(TranscendentalCache::LOG, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005845}
5846
5847
ager@chromium.org5aa501c2009-06-23 07:57:28 +00005848// Helper function to compute x^y, where y is known to be an
5849// integer. Uses binary decomposition to limit the number of
5850// multiplications; see the discussion in "Hacker's Delight" by Henry
5851// S. Warren, Jr., figure 11-6, page 213.
5852static double powi(double x, int y) {
5853 ASSERT(y != kMinInt);
5854 unsigned n = (y < 0) ? -y : y;
5855 double m = x;
5856 double p = 1;
5857 while (true) {
5858 if ((n & 1) != 0) p *= m;
5859 n >>= 1;
5860 if (n == 0) {
5861 if (y < 0) {
5862 // Unfortunately, we have to be careful when p has reached
5863 // infinity in the computation, because sometimes the higher
5864 // internal precision in the pow() implementation would have
5865 // given us a finite p. This happens very rarely.
5866 double result = 1.0 / p;
5867 return (result == 0 && isinf(p))
5868 ? pow(x, static_cast<double>(y)) // Avoid pow(double, int).
5869 : result;
5870 } else {
5871 return p;
5872 }
5873 }
5874 m *= m;
5875 }
5876}
5877
5878
lrn@chromium.org303ada72010-10-27 09:33:13 +00005879static MaybeObject* Runtime_Math_pow(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005880 NoHandleAllocation ha;
5881 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005882 Counters::math_pow.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005883
5884 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00005885
5886 // If the second argument is a smi, it is much faster to call the
5887 // custom powi() function than the generic pow().
5888 if (args[1]->IsSmi()) {
5889 int y = Smi::cast(args[1])->value();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00005890 return Heap::NumberFromDouble(powi(x, y));
ager@chromium.org5aa501c2009-06-23 07:57:28 +00005891 }
5892
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005893 CONVERT_DOUBLE_CHECKED(y, args[1]);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00005894
5895 if (!isinf(x)) {
5896 if (y == 0.5) {
5897 // It's not uncommon to use Math.pow(x, 0.5) to compute the
5898 // square root of a number. To speed up such computations, we
5899 // explictly check for this case and use the sqrt() function
5900 // which is faster than pow().
5901 return Heap::AllocateHeapNumber(sqrt(x));
5902 } else if (y == -0.5) {
5903 // Optimized using Math.pow(x, -0.5) == 1 / Math.pow(x, 0.5).
5904 return Heap::AllocateHeapNumber(1.0 / sqrt(x));
5905 }
5906 }
5907
5908 if (y == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005909 return Smi::FromInt(1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00005910 } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
5911 return Heap::nan_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005912 } else {
5913 return Heap::AllocateHeapNumber(pow(x, y));
5914 }
5915}
5916
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005917// Fast version of Math.pow if we know that y is not an integer and
5918// y is not -0.5 or 0.5. Used as slowcase from codegen.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005919static MaybeObject* Runtime_Math_pow_cfunction(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005920 NoHandleAllocation ha;
5921 ASSERT(args.length() == 2);
5922 CONVERT_DOUBLE_CHECKED(x, args[0]);
5923 CONVERT_DOUBLE_CHECKED(y, args[1]);
5924 if (y == 0) {
5925 return Smi::FromInt(1);
5926 } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
5927 return Heap::nan_value();
5928 } else {
5929 return Heap::AllocateHeapNumber(pow(x, y));
5930 }
5931}
5932
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005933
lrn@chromium.org303ada72010-10-27 09:33:13 +00005934static MaybeObject* Runtime_RoundNumber(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005935 NoHandleAllocation ha;
5936 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005937 Counters::math_round.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005938
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00005939 if (!args[0]->IsHeapNumber()) {
5940 // Must be smi. Return the argument unchanged for all the other types
5941 // to make fuzz-natives test happy.
5942 return args[0];
5943 }
5944
5945 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
5946
5947 double value = number->value();
5948 int exponent = number->get_exponent();
5949 int sign = number->get_sign();
5950
5951 // We compare with kSmiValueSize - 3 because (2^30 - 0.1) has exponent 29 and
5952 // should be rounded to 2^30, which is not smi.
5953 if (!sign && exponent <= kSmiValueSize - 3) {
5954 return Smi::FromInt(static_cast<int>(value + 0.5));
5955 }
5956
5957 // If the magnitude is big enough, there's no place for fraction part. If we
5958 // try to add 0.5 to this number, 1.0 will be added instead.
5959 if (exponent >= 52) {
5960 return number;
5961 }
5962
5963 if (sign && value >= -0.5) return Heap::minus_zero_value();
5964
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00005965 // Do not call NumberFromDouble() to avoid extra checks.
5966 return Heap::AllocateHeapNumber(floor(value + 0.5));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005967}
5968
5969
lrn@chromium.org303ada72010-10-27 09:33:13 +00005970static MaybeObject* Runtime_Math_sin(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005971 NoHandleAllocation ha;
5972 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005973 Counters::math_sin.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005974
5975 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005976 return TranscendentalCache::Get(TranscendentalCache::SIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005977}
5978
5979
lrn@chromium.org303ada72010-10-27 09:33:13 +00005980static MaybeObject* Runtime_Math_sqrt(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005981 NoHandleAllocation ha;
5982 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005983 Counters::math_sqrt.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005984
5985 CONVERT_DOUBLE_CHECKED(x, args[0]);
5986 return Heap::AllocateHeapNumber(sqrt(x));
5987}
5988
5989
lrn@chromium.org303ada72010-10-27 09:33:13 +00005990static MaybeObject* Runtime_Math_tan(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005991 NoHandleAllocation ha;
5992 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005993 Counters::math_tan.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005994
5995 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005996 return TranscendentalCache::Get(TranscendentalCache::TAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005997}
5998
5999
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006000static int MakeDay(int year, int month, int day) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006001 static const int day_from_month[] = {0, 31, 59, 90, 120, 151,
6002 181, 212, 243, 273, 304, 334};
6003 static const int day_from_month_leap[] = {0, 31, 60, 91, 121, 152,
6004 182, 213, 244, 274, 305, 335};
6005
6006 year += month / 12;
6007 month %= 12;
6008 if (month < 0) {
6009 year--;
6010 month += 12;
6011 }
6012
6013 ASSERT(month >= 0);
6014 ASSERT(month < 12);
6015
6016 // year_delta is an arbitrary number such that:
6017 // a) year_delta = -1 (mod 400)
6018 // b) year + year_delta > 0 for years in the range defined by
6019 // ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of
6020 // Jan 1 1970. This is required so that we don't run into integer
6021 // division of negative numbers.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006022 // c) there shouldn't be an overflow for 32-bit integers in the following
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006023 // operations.
6024 static const int year_delta = 399999;
6025 static const int base_day = 365 * (1970 + year_delta) +
6026 (1970 + year_delta) / 4 -
6027 (1970 + year_delta) / 100 +
6028 (1970 + year_delta) / 400;
6029
6030 int year1 = year + year_delta;
6031 int day_from_year = 365 * year1 +
6032 year1 / 4 -
6033 year1 / 100 +
6034 year1 / 400 -
6035 base_day;
6036
6037 if (year % 4 || (year % 100 == 0 && year % 400 != 0)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006038 return day_from_year + day_from_month[month] + day - 1;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006039 }
6040
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006041 return day_from_year + day_from_month_leap[month] + day - 1;
6042}
6043
6044
lrn@chromium.org303ada72010-10-27 09:33:13 +00006045static MaybeObject* Runtime_DateMakeDay(Arguments args) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006046 NoHandleAllocation ha;
6047 ASSERT(args.length() == 3);
6048
6049 CONVERT_SMI_CHECKED(year, args[0]);
6050 CONVERT_SMI_CHECKED(month, args[1]);
6051 CONVERT_SMI_CHECKED(date, args[2]);
6052
6053 return Smi::FromInt(MakeDay(year, month, date));
6054}
6055
6056
6057static const int kDays4Years[] = {0, 365, 2 * 365, 3 * 365 + 1};
6058static const int kDaysIn4Years = 4 * 365 + 1;
6059static const int kDaysIn100Years = 25 * kDaysIn4Years - 1;
6060static const int kDaysIn400Years = 4 * kDaysIn100Years + 1;
6061static const int kDays1970to2000 = 30 * 365 + 7;
6062static const int kDaysOffset = 1000 * kDaysIn400Years + 5 * kDaysIn400Years -
6063 kDays1970to2000;
6064static const int kYearsOffset = 400000;
6065
6066static const char kDayInYear[] = {
6067 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6068 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6069 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6070 22, 23, 24, 25, 26, 27, 28,
6071 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6072 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6073 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6074 22, 23, 24, 25, 26, 27, 28, 29, 30,
6075 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6076 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6077 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6078 22, 23, 24, 25, 26, 27, 28, 29, 30,
6079 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6080 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6081 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6082 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6083 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6084 22, 23, 24, 25, 26, 27, 28, 29, 30,
6085 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6086 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6087 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6088 22, 23, 24, 25, 26, 27, 28, 29, 30,
6089 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6090 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6091
6092 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6093 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6094 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6095 22, 23, 24, 25, 26, 27, 28,
6096 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6097 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6098 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6099 22, 23, 24, 25, 26, 27, 28, 29, 30,
6100 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6101 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6102 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6103 22, 23, 24, 25, 26, 27, 28, 29, 30,
6104 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6105 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6106 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6107 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6108 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6109 22, 23, 24, 25, 26, 27, 28, 29, 30,
6110 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6111 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6112 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6113 22, 23, 24, 25, 26, 27, 28, 29, 30,
6114 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6115 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6116
6117 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6118 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6119 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6120 22, 23, 24, 25, 26, 27, 28, 29,
6121 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6122 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6123 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6124 22, 23, 24, 25, 26, 27, 28, 29, 30,
6125 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6126 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6127 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6128 22, 23, 24, 25, 26, 27, 28, 29, 30,
6129 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6130 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6131 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6132 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6133 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6134 22, 23, 24, 25, 26, 27, 28, 29, 30,
6135 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6136 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6137 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6138 22, 23, 24, 25, 26, 27, 28, 29, 30,
6139 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6140 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6141
6142 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6143 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6144 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6145 22, 23, 24, 25, 26, 27, 28,
6146 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6147 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6148 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6149 22, 23, 24, 25, 26, 27, 28, 29, 30,
6150 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6151 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6152 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6153 22, 23, 24, 25, 26, 27, 28, 29, 30,
6154 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6155 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6156 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6157 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6158 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6159 22, 23, 24, 25, 26, 27, 28, 29, 30,
6160 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6161 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6162 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6163 22, 23, 24, 25, 26, 27, 28, 29, 30,
6164 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6165 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
6166
6167static const char kMonthInYear[] = {
6168 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,
6169 0, 0, 0, 0, 0, 0,
6170 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,
6171 1, 1, 1,
6172 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,
6173 2, 2, 2, 2, 2, 2,
6174 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,
6175 3, 3, 3, 3, 3,
6176 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,
6177 4, 4, 4, 4, 4, 4,
6178 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,
6179 5, 5, 5, 5, 5,
6180 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,
6181 6, 6, 6, 6, 6, 6,
6182 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,
6183 7, 7, 7, 7, 7, 7,
6184 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,
6185 8, 8, 8, 8, 8,
6186 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,
6187 9, 9, 9, 9, 9, 9,
6188 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6189 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6190 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6191 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6192
6193 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,
6194 0, 0, 0, 0, 0, 0,
6195 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,
6196 1, 1, 1,
6197 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,
6198 2, 2, 2, 2, 2, 2,
6199 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,
6200 3, 3, 3, 3, 3,
6201 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,
6202 4, 4, 4, 4, 4, 4,
6203 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,
6204 5, 5, 5, 5, 5,
6205 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,
6206 6, 6, 6, 6, 6, 6,
6207 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,
6208 7, 7, 7, 7, 7, 7,
6209 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,
6210 8, 8, 8, 8, 8,
6211 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,
6212 9, 9, 9, 9, 9, 9,
6213 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6214 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6215 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6216 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6217
6218 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,
6219 0, 0, 0, 0, 0, 0,
6220 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,
6221 1, 1, 1, 1,
6222 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,
6223 2, 2, 2, 2, 2, 2,
6224 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,
6225 3, 3, 3, 3, 3,
6226 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,
6227 4, 4, 4, 4, 4, 4,
6228 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,
6229 5, 5, 5, 5, 5,
6230 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,
6231 6, 6, 6, 6, 6, 6,
6232 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,
6233 7, 7, 7, 7, 7, 7,
6234 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,
6235 8, 8, 8, 8, 8,
6236 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,
6237 9, 9, 9, 9, 9, 9,
6238 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6239 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6240 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6241 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6242
6243 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,
6244 0, 0, 0, 0, 0, 0,
6245 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,
6246 1, 1, 1,
6247 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,
6248 2, 2, 2, 2, 2, 2,
6249 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,
6250 3, 3, 3, 3, 3,
6251 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,
6252 4, 4, 4, 4, 4, 4,
6253 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,
6254 5, 5, 5, 5, 5,
6255 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,
6256 6, 6, 6, 6, 6, 6,
6257 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,
6258 7, 7, 7, 7, 7, 7,
6259 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,
6260 8, 8, 8, 8, 8,
6261 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,
6262 9, 9, 9, 9, 9, 9,
6263 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6264 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6265 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6266 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11};
6267
6268
6269// This function works for dates from 1970 to 2099.
6270static inline void DateYMDFromTimeAfter1970(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006271 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006272#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00006273 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006274#endif
6275
6276 year = 1970 + (4 * date + 2) / kDaysIn4Years;
6277 date %= kDaysIn4Years;
6278
6279 month = kMonthInYear[date];
6280 day = kDayInYear[date];
6281
6282 ASSERT(MakeDay(year, month, day) == save_date);
6283}
6284
6285
6286static inline void DateYMDFromTimeSlow(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006287 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006288#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00006289 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006290#endif
6291
6292 date += kDaysOffset;
6293 year = 400 * (date / kDaysIn400Years) - kYearsOffset;
6294 date %= kDaysIn400Years;
6295
6296 ASSERT(MakeDay(year, 0, 1) + date == save_date);
6297
6298 date--;
6299 int yd1 = date / kDaysIn100Years;
6300 date %= kDaysIn100Years;
6301 year += 100 * yd1;
6302
6303 date++;
6304 int yd2 = date / kDaysIn4Years;
6305 date %= kDaysIn4Years;
6306 year += 4 * yd2;
6307
6308 date--;
6309 int yd3 = date / 365;
6310 date %= 365;
6311 year += yd3;
6312
6313 bool is_leap = (!yd1 || yd2) && !yd3;
6314
6315 ASSERT(date >= -1);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006316 ASSERT(is_leap || (date >= 0));
6317 ASSERT((date < 365) || (is_leap && (date < 366)));
6318 ASSERT(is_leap == ((year % 4 == 0) && (year % 100 || (year % 400 == 0))));
6319 ASSERT(is_leap || ((MakeDay(year, 0, 1) + date) == save_date));
6320 ASSERT(!is_leap || ((MakeDay(year, 0, 1) + date + 1) == save_date));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006321
6322 if (is_leap) {
6323 day = kDayInYear[2*365 + 1 + date];
6324 month = kMonthInYear[2*365 + 1 + date];
6325 } else {
6326 day = kDayInYear[date];
6327 month = kMonthInYear[date];
6328 }
6329
6330 ASSERT(MakeDay(year, month, day) == save_date);
6331}
6332
6333
6334static inline void DateYMDFromTime(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006335 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006336 if (date >= 0 && date < 32 * kDaysIn4Years) {
6337 DateYMDFromTimeAfter1970(date, year, month, day);
6338 } else {
6339 DateYMDFromTimeSlow(date, year, month, day);
6340 }
6341}
6342
6343
lrn@chromium.org303ada72010-10-27 09:33:13 +00006344static MaybeObject* Runtime_DateYMDFromTime(Arguments args) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006345 NoHandleAllocation ha;
6346 ASSERT(args.length() == 2);
6347
6348 CONVERT_DOUBLE_CHECKED(t, args[0]);
6349 CONVERT_CHECKED(JSArray, res_array, args[1]);
6350
6351 int year, month, day;
6352 DateYMDFromTime(static_cast<int>(floor(t / 86400000)), year, month, day);
6353
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00006354 RUNTIME_ASSERT(res_array->elements()->map() == Heap::fixed_array_map());
6355 FixedArray* elms = FixedArray::cast(res_array->elements());
6356 RUNTIME_ASSERT(elms->length() == 3);
6357
6358 elms->set(0, Smi::FromInt(year));
6359 elms->set(1, Smi::FromInt(month));
6360 elms->set(2, Smi::FromInt(day));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006361
6362 return Heap::undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006363}
6364
6365
lrn@chromium.org303ada72010-10-27 09:33:13 +00006366static MaybeObject* Runtime_NewArgumentsFast(Arguments args) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00006367 NoHandleAllocation ha;
6368 ASSERT(args.length() == 3);
6369
6370 JSFunction* callee = JSFunction::cast(args[0]);
6371 Object** parameters = reinterpret_cast<Object**>(args[1]);
6372 const int length = Smi::cast(args[2])->value();
6373
lrn@chromium.org303ada72010-10-27 09:33:13 +00006374 Object* result;
6375 { MaybeObject* maybe_result = Heap::AllocateArgumentsObject(callee, length);
6376 if (!maybe_result->ToObject(&result)) return maybe_result;
6377 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006378 // Allocate the elements if needed.
6379 if (length > 0) {
6380 // Allocate the fixed array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006381 Object* obj;
6382 { MaybeObject* maybe_obj = Heap::AllocateRawFixedArray(length);
6383 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6384 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006385
6386 AssertNoAllocation no_gc;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006387 FixedArray* array = reinterpret_cast<FixedArray*>(obj);
6388 array->set_map(Heap::fixed_array_map());
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006389 array->set_length(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006390
6391 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006392 for (int i = 0; i < length; i++) {
6393 array->set(i, *--parameters, mode);
6394 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006395 JSObject::cast(result)->set_elements(FixedArray::cast(obj));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00006396 }
6397 return result;
6398}
6399
6400
lrn@chromium.org303ada72010-10-27 09:33:13 +00006401static MaybeObject* Runtime_NewClosure(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006402 HandleScope scope;
6403 ASSERT(args.length() == 2);
ager@chromium.org3811b432009-10-28 14:53:37 +00006404 CONVERT_ARG_CHECKED(Context, context, 0);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00006405 CONVERT_ARG_CHECKED(SharedFunctionInfo, shared, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006406
sgjesse@chromium.org846fb742009-12-18 08:56:33 +00006407 PretenureFlag pretenure = (context->global_context() == *context)
6408 ? TENURED // Allocate global closures in old space.
6409 : NOT_TENURED; // Allocate local closures in new space.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006410 Handle<JSFunction> result =
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00006411 Factory::NewFunctionFromSharedFunctionInfo(shared, context, pretenure);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006412 return *result;
6413}
6414
lrn@chromium.org303ada72010-10-27 09:33:13 +00006415static MaybeObject* Runtime_NewObjectFromBound(Arguments args) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006416 HandleScope scope;
6417 ASSERT(args.length() == 2);
6418 CONVERT_ARG_CHECKED(JSFunction, function, 0);
6419 CONVERT_ARG_CHECKED(JSArray, params, 1);
6420
whesse@chromium.orge90029b2010-08-02 11:52:17 +00006421 RUNTIME_ASSERT(params->HasFastElements());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006422 FixedArray* fixed = FixedArray::cast(params->elements());
6423
whesse@chromium.orge90029b2010-08-02 11:52:17 +00006424 int fixed_length = Smi::cast(params->length())->value();
6425 SmartPointer<Object**> param_data(NewArray<Object**>(fixed_length));
6426 for (int i = 0; i < fixed_length; i++) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006427 Handle<Object> val = Handle<Object>(fixed->get(i));
6428 param_data[i] = val.location();
6429 }
6430
whesse@chromium.orge90029b2010-08-02 11:52:17 +00006431 bool exception = false;
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006432 Handle<Object> result = Execution::New(
whesse@chromium.orge90029b2010-08-02 11:52:17 +00006433 function, fixed_length, *param_data, &exception);
6434 if (exception) {
6435 return Failure::Exception();
6436 }
6437 ASSERT(!result.is_null());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006438 return *result;
6439}
6440
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006441
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006442static void TrySettingInlineConstructStub(Handle<JSFunction> function) {
ager@chromium.org5c838252010-02-19 08:53:10 +00006443 Handle<Object> prototype = Factory::null_value();
6444 if (function->has_instance_prototype()) {
6445 prototype = Handle<Object>(function->instance_prototype());
6446 }
6447 if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006448 ConstructStubCompiler compiler;
lrn@chromium.org303ada72010-10-27 09:33:13 +00006449 MaybeObject* code = compiler.CompileConstructStub(function->shared());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006450 if (!code->IsFailure()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00006451 function->shared()->set_construct_stub(
6452 Code::cast(code->ToObjectUnchecked()));
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006453 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006454 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006455}
6456
6457
lrn@chromium.org303ada72010-10-27 09:33:13 +00006458static MaybeObject* Runtime_NewObject(Arguments args) {
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006459 HandleScope scope;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006460 ASSERT(args.length() == 1);
6461
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006462 Handle<Object> constructor = args.at<Object>(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006463
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006464 // If the constructor isn't a proper function we throw a type error.
6465 if (!constructor->IsJSFunction()) {
6466 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
6467 Handle<Object> type_error =
6468 Factory::NewTypeError("not_constructor", arguments);
6469 return Top::Throw(*type_error);
6470 }
6471
6472 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006473
6474 // If function should not have prototype, construction is not allowed. In this
6475 // case generated code bailouts here, since function has no initial_map.
6476 if (!function->should_have_prototype()) {
6477 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
6478 Handle<Object> type_error =
6479 Factory::NewTypeError("not_constructor", arguments);
6480 return Top::Throw(*type_error);
6481 }
6482
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006483#ifdef ENABLE_DEBUGGER_SUPPORT
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006484 // Handle stepping into constructors if step into is active.
6485 if (Debug::StepInActive()) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006486 Debug::HandleStepIn(function, Handle<Object>::null(), 0, true);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006487 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006488#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006489
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006490 if (function->has_initial_map()) {
6491 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006492 // The 'Function' function ignores the receiver object when
6493 // called using 'new' and creates a new JSFunction object that
6494 // is returned. The receiver object is only used for error
6495 // reporting if an error occurs when constructing the new
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006496 // JSFunction. Factory::NewJSObject() should not be used to
6497 // allocate JSFunctions since it does not properly initialize
6498 // the shared part of the function. Since the receiver is
6499 // ignored anyway, we use the global object as the receiver
6500 // instead of a new JSFunction object. This way, errors are
6501 // reported the same way whether or not 'Function' is called
6502 // using 'new'.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006503 return Top::context()->global();
6504 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006505 }
6506
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006507 // The function should be compiled for the optimization hints to be available.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006508 Handle<SharedFunctionInfo> shared(function->shared());
6509 EnsureCompiled(shared, CLEAR_EXCEPTION);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006510
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006511 if (!function->has_initial_map() &&
6512 shared->IsInobjectSlackTrackingInProgress()) {
6513 // The tracking is already in progress for another function. We can only
6514 // track one initial_map at a time, so we force the completion before the
6515 // function is called as a constructor for the first time.
6516 shared->CompleteInobjectSlackTracking();
6517 TrySettingInlineConstructStub(function);
6518 }
6519
6520 bool first_allocation = !shared->live_objects_may_exist();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006521 Handle<JSObject> result = Factory::NewJSObject(function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006522 // Delay setting the stub if inobject slack tracking is in progress.
6523 if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) {
6524 TrySettingInlineConstructStub(function);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006525 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006526
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00006527 Counters::constructed_objects.Increment();
6528 Counters::constructed_objects_runtime.Increment();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006529
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006530 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006531}
6532
6533
lrn@chromium.org303ada72010-10-27 09:33:13 +00006534static MaybeObject* Runtime_FinalizeInstanceSize(Arguments args) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006535 HandleScope scope;
6536 ASSERT(args.length() == 1);
6537
6538 CONVERT_ARG_CHECKED(JSFunction, function, 0);
6539 function->shared()->CompleteInobjectSlackTracking();
6540 TrySettingInlineConstructStub(function);
6541
6542 return Heap::undefined_value();
6543}
6544
6545
lrn@chromium.org303ada72010-10-27 09:33:13 +00006546static MaybeObject* Runtime_LazyCompile(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006547 HandleScope scope;
6548 ASSERT(args.length() == 1);
6549
6550 Handle<JSFunction> function = args.at<JSFunction>(0);
6551#ifdef DEBUG
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00006552 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006553 PrintF("[lazy: ");
6554 function->shared()->name()->Print();
6555 PrintF("]\n");
6556 }
6557#endif
6558
kasperl@chromium.org71affb52009-05-26 05:44:31 +00006559 // Compile the target function. Here we compile using CompileLazyInLoop in
6560 // order to get the optimized version. This helps code like delta-blue
6561 // that calls performance-critical routines through constructors. A
6562 // constructor call doesn't use a CallIC, it uses a LoadIC followed by a
6563 // direct call. Since the in-loop tracking takes place through CallICs
6564 // this means that things called through constructors are never known to
6565 // be in loops. We compile them as if they are in loops here just in case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006566 ASSERT(!function->is_compiled());
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00006567 if (!CompileLazyInLoop(function, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006568 return Failure::Exception();
6569 }
6570
6571 return function->code();
6572}
6573
6574
lrn@chromium.org303ada72010-10-27 09:33:13 +00006575static MaybeObject* Runtime_GetFunctionDelegate(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006576 HandleScope scope;
6577 ASSERT(args.length() == 1);
6578 RUNTIME_ASSERT(!args[0]->IsJSFunction());
6579 return *Execution::GetFunctionDelegate(args.at<Object>(0));
6580}
6581
6582
lrn@chromium.org303ada72010-10-27 09:33:13 +00006583static MaybeObject* Runtime_GetConstructorDelegate(Arguments args) {
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00006584 HandleScope scope;
6585 ASSERT(args.length() == 1);
6586 RUNTIME_ASSERT(!args[0]->IsJSFunction());
6587 return *Execution::GetConstructorDelegate(args.at<Object>(0));
6588}
6589
6590
lrn@chromium.org303ada72010-10-27 09:33:13 +00006591static MaybeObject* Runtime_NewContext(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006592 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00006593 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006594
kasper.lund7276f142008-07-30 08:49:36 +00006595 CONVERT_CHECKED(JSFunction, function, args[0]);
ager@chromium.orgb5737492010-07-15 09:29:43 +00006596 int length = function->shared()->scope_info()->NumberOfContextSlots();
lrn@chromium.org303ada72010-10-27 09:33:13 +00006597 Object* result;
6598 { MaybeObject* maybe_result = Heap::AllocateFunctionContext(length, function);
6599 if (!maybe_result->ToObject(&result)) return maybe_result;
6600 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006601
6602 Top::set_context(Context::cast(result));
6603
kasper.lund7276f142008-07-30 08:49:36 +00006604 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006605}
6606
lrn@chromium.org303ada72010-10-27 09:33:13 +00006607
6608MUST_USE_RESULT static MaybeObject* PushContextHelper(Object* object,
6609 bool is_catch_context) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006610 // Convert the object to a proper JavaScript object.
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00006611 Object* js_object = object;
6612 if (!js_object->IsJSObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00006613 MaybeObject* maybe_js_object = js_object->ToObject();
6614 if (!maybe_js_object->ToObject(&js_object)) {
6615 if (!Failure::cast(maybe_js_object)->IsInternalError()) {
6616 return maybe_js_object;
6617 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006618 HandleScope scope;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00006619 Handle<Object> handle(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006620 Handle<Object> result =
6621 Factory::NewTypeError("with_expression", HandleVector(&handle, 1));
6622 return Top::Throw(*result);
6623 }
6624 }
6625
lrn@chromium.org303ada72010-10-27 09:33:13 +00006626 Object* result;
6627 { MaybeObject* maybe_result =
6628 Heap::AllocateWithContext(Top::context(),
6629 JSObject::cast(js_object),
6630 is_catch_context);
6631 if (!maybe_result->ToObject(&result)) return maybe_result;
6632 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006633
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00006634 Context* context = Context::cast(result);
6635 Top::set_context(context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006636
kasper.lund7276f142008-07-30 08:49:36 +00006637 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006638}
6639
6640
lrn@chromium.org303ada72010-10-27 09:33:13 +00006641static MaybeObject* Runtime_PushContext(Arguments args) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00006642 NoHandleAllocation ha;
6643 ASSERT(args.length() == 1);
6644 return PushContextHelper(args[0], false);
6645}
6646
6647
lrn@chromium.org303ada72010-10-27 09:33:13 +00006648static MaybeObject* Runtime_PushCatchContext(Arguments args) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00006649 NoHandleAllocation ha;
6650 ASSERT(args.length() == 1);
6651 return PushContextHelper(args[0], true);
6652}
6653
6654
lrn@chromium.org303ada72010-10-27 09:33:13 +00006655static MaybeObject* Runtime_LookupContext(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006656 HandleScope scope;
6657 ASSERT(args.length() == 2);
6658
6659 CONVERT_ARG_CHECKED(Context, context, 0);
6660 CONVERT_ARG_CHECKED(String, name, 1);
6661
6662 int index;
6663 PropertyAttributes attributes;
6664 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006665 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006666 context->Lookup(name, flags, &index, &attributes);
6667
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006668 if (index < 0 && !holder.is_null()) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006669 ASSERT(holder->IsJSObject());
6670 return *holder;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006671 }
6672
6673 // No intermediate context found. Use global object by default.
6674 return Top::context()->global();
6675}
6676
6677
ager@chromium.orga1645e22009-09-09 19:27:10 +00006678// A mechanism to return a pair of Object pointers in registers (if possible).
6679// How this is achieved is calling convention-dependent.
6680// All currently supported x86 compiles uses calling conventions that are cdecl
6681// variants where a 64-bit value is returned in two 32-bit registers
6682// (edx:eax on ia32, r1:r0 on ARM).
6683// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
6684// In Win64 calling convention, a struct of two pointers is returned in memory,
6685// allocated by the caller, and passed as a pointer in a hidden first parameter.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00006686#ifdef V8_HOST_ARCH_64_BIT
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00006687struct ObjectPair {
lrn@chromium.org303ada72010-10-27 09:33:13 +00006688 MaybeObject* x;
6689 MaybeObject* y;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00006690};
ager@chromium.orga1645e22009-09-09 19:27:10 +00006691
lrn@chromium.org303ada72010-10-27 09:33:13 +00006692static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00006693 ObjectPair result = {x, y};
ager@chromium.orga1645e22009-09-09 19:27:10 +00006694 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
6695 // In Win64 they are assigned to a hidden first argument.
6696 return result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00006697}
6698#else
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006699typedef uint64_t ObjectPair;
lrn@chromium.org303ada72010-10-27 09:33:13 +00006700static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006701 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006702 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006703}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00006704#endif
6705
6706
lrn@chromium.org303ada72010-10-27 09:33:13 +00006707static inline MaybeObject* Unhole(MaybeObject* x,
6708 PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006709 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
6710 USE(attributes);
6711 return x->IsTheHole() ? Heap::undefined_value() : x;
6712}
6713
6714
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006715static JSObject* ComputeReceiverForNonGlobal(JSObject* holder) {
6716 ASSERT(!holder->IsGlobalObject());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006717 Context* top = Top::context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006718 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006719 JSFunction* context_extension_function =
6720 top->global_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006721 // If the holder isn't a context extension object, we just return it
6722 // as the receiver. This allows arguments objects to be used as
6723 // receivers, but only if they are put in the context scope chain
6724 // explicitly via a with-statement.
6725 Object* constructor = holder->map()->constructor();
6726 if (constructor != context_extension_function) return holder;
6727 // Fall back to using the global object as the receiver if the
6728 // property turns out to be a local variable allocated in a context
6729 // extension object - introduced via eval.
6730 return top->global()->global_receiver();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006731}
6732
6733
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006734static ObjectPair LoadContextSlotHelper(Arguments args, bool throw_error) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006735 HandleScope scope;
ager@chromium.orga1645e22009-09-09 19:27:10 +00006736 ASSERT_EQ(2, args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006737
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006738 if (!args[0]->IsContext() || !args[1]->IsString()) {
ager@chromium.org3e875802009-06-29 08:26:34 +00006739 return MakePair(Top::ThrowIllegalOperation(), NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006740 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006741 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006742 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006743
6744 int index;
6745 PropertyAttributes attributes;
6746 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006747 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006748 context->Lookup(name, flags, &index, &attributes);
6749
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006750 // If the index is non-negative, the slot has been found in a local
6751 // variable or a parameter. Read it from the context object or the
6752 // arguments object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006753 if (index >= 0) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006754 // If the "property" we were looking for is a local variable or an
6755 // argument in a context, the receiver is the global object; see
6756 // ECMA-262, 3rd., 10.1.6 and 10.2.3.
6757 JSObject* receiver = Top::context()->global()->global_receiver();
lrn@chromium.org303ada72010-10-27 09:33:13 +00006758 MaybeObject* value = (holder->IsContext())
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006759 ? Context::cast(*holder)->get(index)
6760 : JSObject::cast(*holder)->GetElement(index);
6761 return MakePair(Unhole(value, attributes), receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006762 }
6763
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006764 // If the holder is found, we read the property from it.
6765 if (!holder.is_null() && holder->IsJSObject()) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00006766 ASSERT(Handle<JSObject>::cast(holder)->HasProperty(*name));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006767 JSObject* object = JSObject::cast(*holder);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00006768 JSObject* receiver;
6769 if (object->IsGlobalObject()) {
6770 receiver = GlobalObject::cast(object)->global_receiver();
6771 } else if (context->is_exception_holder(*holder)) {
6772 receiver = Top::context()->global()->global_receiver();
6773 } else {
6774 receiver = ComputeReceiverForNonGlobal(object);
6775 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006776 // No need to unhole the value here. This is taken care of by the
6777 // GetProperty function.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006778 MaybeObject* value = object->GetProperty(*name);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006779 return MakePair(value, receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006780 }
6781
6782 if (throw_error) {
6783 // The property doesn't exist - throw exception.
6784 Handle<Object> reference_error =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006785 Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006786 return MakePair(Top::Throw(*reference_error), NULL);
6787 } else {
6788 // The property doesn't exist - return undefined
6789 return MakePair(Heap::undefined_value(), Heap::undefined_value());
6790 }
6791}
6792
6793
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006794static ObjectPair Runtime_LoadContextSlot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006795 return LoadContextSlotHelper(args, true);
6796}
6797
6798
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006799static ObjectPair Runtime_LoadContextSlotNoReferenceError(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006800 return LoadContextSlotHelper(args, false);
6801}
6802
6803
lrn@chromium.org303ada72010-10-27 09:33:13 +00006804static MaybeObject* Runtime_StoreContextSlot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006805 HandleScope scope;
6806 ASSERT(args.length() == 3);
6807
6808 Handle<Object> value(args[0]);
6809 CONVERT_ARG_CHECKED(Context, context, 1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006810 CONVERT_ARG_CHECKED(String, name, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006811
6812 int index;
6813 PropertyAttributes attributes;
6814 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006815 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006816 context->Lookup(name, flags, &index, &attributes);
6817
6818 if (index >= 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006819 if (holder->IsContext()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006820 // Ignore if read_only variable.
6821 if ((attributes & READ_ONLY) == 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006822 Handle<Context>::cast(holder)->set(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006823 }
6824 } else {
6825 ASSERT((attributes & READ_ONLY) == 0);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006826 Handle<JSObject>::cast(holder)->SetElement(index, *value)->
6827 ToObjectUnchecked();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006828 }
6829 return *value;
6830 }
6831
6832 // Slow case: The property is not in a FixedArray context.
6833 // It is either in an JSObject extension context or it was not found.
6834 Handle<JSObject> context_ext;
6835
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006836 if (!holder.is_null()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006837 // The property exists in the extension context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006838 context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006839 } else {
6840 // The property was not found. It needs to be stored in the global context.
6841 ASSERT(attributes == ABSENT);
6842 attributes = NONE;
6843 context_ext = Handle<JSObject>(Top::context()->global());
6844 }
6845
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006846 // Set the property, but ignore if read_only variable on the context
6847 // extension object itself.
6848 if ((attributes & READ_ONLY) == 0 ||
6849 (context_ext->GetLocalPropertyAttribute(*name) == ABSENT)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006850 Handle<Object> set = SetProperty(context_ext, name, value, attributes);
6851 if (set.is_null()) {
6852 // Failure::Exception is converted to a null handle in the
6853 // handle-based methods such as SetProperty. We therefore need
6854 // to convert null handles back to exceptions.
6855 ASSERT(Top::has_pending_exception());
6856 return Failure::Exception();
6857 }
6858 }
6859 return *value;
6860}
6861
6862
lrn@chromium.org303ada72010-10-27 09:33:13 +00006863static MaybeObject* Runtime_Throw(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006864 HandleScope scope;
6865 ASSERT(args.length() == 1);
6866
6867 return Top::Throw(args[0]);
6868}
6869
6870
lrn@chromium.org303ada72010-10-27 09:33:13 +00006871static MaybeObject* Runtime_ReThrow(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006872 HandleScope scope;
6873 ASSERT(args.length() == 1);
6874
6875 return Top::ReThrow(args[0]);
6876}
6877
6878
lrn@chromium.org303ada72010-10-27 09:33:13 +00006879static MaybeObject* Runtime_PromoteScheduledException(Arguments args) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006880 ASSERT_EQ(0, args.length());
6881 return Top::PromoteScheduledException();
6882}
6883
6884
lrn@chromium.org303ada72010-10-27 09:33:13 +00006885static MaybeObject* Runtime_ThrowReferenceError(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006886 HandleScope scope;
6887 ASSERT(args.length() == 1);
6888
6889 Handle<Object> name(args[0]);
6890 Handle<Object> reference_error =
6891 Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
6892 return Top::Throw(*reference_error);
6893}
6894
6895
lrn@chromium.org303ada72010-10-27 09:33:13 +00006896static MaybeObject* Runtime_StackOverflow(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006897 NoHandleAllocation na;
6898 return Top::StackOverflow();
6899}
6900
6901
lrn@chromium.org303ada72010-10-27 09:33:13 +00006902static MaybeObject* Runtime_StackGuard(Arguments args) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00006903 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006904
6905 // First check if this is a real stack overflow.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00006906 if (StackGuard::IsStackOverflow()) {
6907 return Runtime_StackOverflow(args);
6908 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006909
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00006910 return Execution::HandleStackGuardInterrupt();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006911}
6912
6913
6914// NOTE: These PrintXXX functions are defined for all builds (not just
6915// DEBUG builds) because we may want to be able to trace function
6916// calls in all modes.
6917static void PrintString(String* str) {
6918 // not uncommon to have empty strings
6919 if (str->length() > 0) {
6920 SmartPointer<char> s =
6921 str->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
6922 PrintF("%s", *s);
6923 }
6924}
6925
6926
6927static void PrintObject(Object* obj) {
6928 if (obj->IsSmi()) {
6929 PrintF("%d", Smi::cast(obj)->value());
6930 } else if (obj->IsString() || obj->IsSymbol()) {
6931 PrintString(String::cast(obj));
6932 } else if (obj->IsNumber()) {
6933 PrintF("%g", obj->Number());
6934 } else if (obj->IsFailure()) {
6935 PrintF("<failure>");
6936 } else if (obj->IsUndefined()) {
6937 PrintF("<undefined>");
6938 } else if (obj->IsNull()) {
6939 PrintF("<null>");
6940 } else if (obj->IsTrue()) {
6941 PrintF("<true>");
6942 } else if (obj->IsFalse()) {
6943 PrintF("<false>");
6944 } else {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00006945 PrintF("%p", reinterpret_cast<void*>(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006946 }
6947}
6948
6949
6950static int StackSize() {
6951 int n = 0;
6952 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
6953 return n;
6954}
6955
6956
6957static void PrintTransition(Object* result) {
6958 // indentation
6959 { const int nmax = 80;
6960 int n = StackSize();
6961 if (n <= nmax)
6962 PrintF("%4d:%*s", n, n, "");
6963 else
6964 PrintF("%4d:%*s", n, nmax, "...");
6965 }
6966
6967 if (result == NULL) {
6968 // constructor calls
6969 JavaScriptFrameIterator it;
6970 JavaScriptFrame* frame = it.frame();
6971 if (frame->IsConstructor()) PrintF("new ");
6972 // function name
6973 Object* fun = frame->function();
6974 if (fun->IsJSFunction()) {
6975 PrintObject(JSFunction::cast(fun)->shared()->name());
6976 } else {
6977 PrintObject(fun);
6978 }
6979 // function arguments
6980 // (we are intentionally only printing the actually
6981 // supplied parameters, not all parameters required)
6982 PrintF("(this=");
6983 PrintObject(frame->receiver());
6984 const int length = frame->GetProvidedParametersCount();
6985 for (int i = 0; i < length; i++) {
6986 PrintF(", ");
6987 PrintObject(frame->GetParameter(i));
6988 }
6989 PrintF(") {\n");
6990
6991 } else {
6992 // function result
6993 PrintF("} -> ");
6994 PrintObject(result);
6995 PrintF("\n");
6996 }
6997}
6998
6999
lrn@chromium.org303ada72010-10-27 09:33:13 +00007000static MaybeObject* Runtime_TraceEnter(Arguments args) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007001 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007002 NoHandleAllocation ha;
7003 PrintTransition(NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007004 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007005}
7006
7007
lrn@chromium.org303ada72010-10-27 09:33:13 +00007008static MaybeObject* Runtime_TraceExit(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007009 NoHandleAllocation ha;
7010 PrintTransition(args[0]);
7011 return args[0]; // return TOS
7012}
7013
7014
lrn@chromium.org303ada72010-10-27 09:33:13 +00007015static MaybeObject* Runtime_DebugPrint(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007016 NoHandleAllocation ha;
7017 ASSERT(args.length() == 1);
7018
7019#ifdef DEBUG
7020 if (args[0]->IsString()) {
7021 // If we have a string, assume it's a code "marker"
7022 // and print some interesting cpu debugging info.
7023 JavaScriptFrameIterator it;
7024 JavaScriptFrame* frame = it.frame();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00007025 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
7026 frame->fp(), frame->sp(), frame->caller_sp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007027 } else {
7028 PrintF("DebugPrint: ");
7029 }
7030 args[0]->Print();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00007031 if (args[0]->IsHeapObject()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007032 PrintF("\n");
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00007033 HeapObject::cast(args[0])->map()->Print();
7034 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007035#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007036 // ShortPrint is available in release mode. Print is not.
7037 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007038#endif
7039 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00007040 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007041
7042 return args[0]; // return TOS
7043}
7044
7045
lrn@chromium.org303ada72010-10-27 09:33:13 +00007046static MaybeObject* Runtime_DebugTrace(Arguments args) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007047 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007048 NoHandleAllocation ha;
7049 Top::PrintStack();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007050 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007051}
7052
7053
lrn@chromium.org303ada72010-10-27 09:33:13 +00007054static MaybeObject* Runtime_DateCurrentTime(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007055 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00007056 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007057
7058 // According to ECMA-262, section 15.9.1, page 117, the precision of
7059 // the number in a Date object representing a particular instant in
7060 // time is milliseconds. Therefore, we floor the result of getting
7061 // the OS time.
7062 double millis = floor(OS::TimeCurrentMillis());
7063 return Heap::NumberFromDouble(millis);
7064}
7065
7066
lrn@chromium.org303ada72010-10-27 09:33:13 +00007067static MaybeObject* Runtime_DateParseString(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007068 HandleScope scope;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007069 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007070
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007071 CONVERT_ARG_CHECKED(String, str, 0);
7072 FlattenString(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007073
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007074 CONVERT_ARG_CHECKED(JSArray, output, 1);
7075 RUNTIME_ASSERT(output->HasFastElements());
7076
7077 AssertNoAllocation no_allocation;
7078
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007079 FixedArray* output_array = FixedArray::cast(output->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007080 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
7081 bool result;
ager@chromium.org5ec48922009-05-05 07:25:34 +00007082 if (str->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007083 result = DateParser::Parse(str->ToAsciiVector(), output_array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007084 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00007085 ASSERT(str->IsTwoByteRepresentation());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007086 result = DateParser::Parse(str->ToUC16Vector(), output_array);
7087 }
7088
7089 if (result) {
7090 return *output;
7091 } else {
7092 return Heap::null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007093 }
7094}
7095
7096
lrn@chromium.org303ada72010-10-27 09:33:13 +00007097static MaybeObject* Runtime_DateLocalTimezone(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007098 NoHandleAllocation ha;
7099 ASSERT(args.length() == 1);
7100
7101 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00007102 const char* zone = OS::LocalTimezone(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007103 return Heap::AllocateStringFromUtf8(CStrVector(zone));
7104}
7105
7106
lrn@chromium.org303ada72010-10-27 09:33:13 +00007107static MaybeObject* Runtime_DateLocalTimeOffset(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007108 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00007109 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007110
7111 return Heap::NumberFromDouble(OS::LocalTimeOffset());
7112}
7113
7114
lrn@chromium.org303ada72010-10-27 09:33:13 +00007115static MaybeObject* Runtime_DateDaylightSavingsOffset(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007116 NoHandleAllocation ha;
7117 ASSERT(args.length() == 1);
7118
7119 CONVERT_DOUBLE_CHECKED(x, args[0]);
7120 return Heap::NumberFromDouble(OS::DaylightSavingsOffset(x));
7121}
7122
7123
lrn@chromium.org303ada72010-10-27 09:33:13 +00007124static MaybeObject* Runtime_GlobalReceiver(Arguments args) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007125 ASSERT(args.length() == 1);
7126 Object* global = args[0];
7127 if (!global->IsJSGlobalObject()) return Heap::null_value();
7128 return JSGlobalObject::cast(global)->global_receiver();
7129}
7130
7131
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00007132static MaybeObject* Runtime_ParseJson(Arguments args) {
7133 HandleScope scope;
7134 ASSERT_EQ(1, args.length());
7135 CONVERT_ARG_CHECKED(String, source, 0);
7136
7137 Handle<Object> result = JsonParser::Parse(source);
7138 if (result.is_null()) {
7139 // Syntax error or stack overflow in scanner.
7140 ASSERT(Top::has_pending_exception());
7141 return Failure::Exception();
7142 }
7143 return *result;
7144}
7145
7146
lrn@chromium.org303ada72010-10-27 09:33:13 +00007147static MaybeObject* Runtime_CompileString(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007148 HandleScope scope;
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00007149 ASSERT_EQ(1, args.length());
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00007150 CONVERT_ARG_CHECKED(String, source, 0);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007151
ager@chromium.org381abbb2009-02-25 13:23:22 +00007152 // Compile source string in the global context.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007153 Handle<Context> context(Top::context()->global_context());
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007154 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(source,
7155 context,
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00007156 true);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007157 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007158 Handle<JSFunction> fun =
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007159 Factory::NewFunctionFromSharedFunctionInfo(shared, context, NOT_TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007160 return *fun;
7161}
7162
7163
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00007164static ObjectPair CompileGlobalEval(Handle<String> source,
7165 Handle<Object> receiver) {
7166 // Deal with a normal eval call with a string argument. Compile it
7167 // and return the compiled function bound in the local context.
7168 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
7169 source,
7170 Handle<Context>(Top::context()),
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00007171 Top::context()->IsGlobalContext());
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00007172 if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
7173 Handle<JSFunction> compiled = Factory::NewFunctionFromSharedFunctionInfo(
7174 shared,
7175 Handle<Context>(Top::context()),
7176 NOT_TENURED);
7177 return MakePair(*compiled, *receiver);
7178}
7179
7180
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007181static ObjectPair Runtime_ResolvePossiblyDirectEval(Arguments args) {
7182 ASSERT(args.length() == 3);
7183 if (!args[0]->IsJSFunction()) {
7184 return MakePair(Top::ThrowIllegalOperation(), NULL);
7185 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007186
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007187 HandleScope scope;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007188 Handle<JSFunction> callee = args.at<JSFunction>(0);
7189 Handle<Object> receiver; // Will be overwritten.
7190
7191 // Compute the calling context.
7192 Handle<Context> context = Handle<Context>(Top::context());
7193#ifdef DEBUG
7194 // Make sure Top::context() agrees with the old code that traversed
7195 // the stack frames to compute the context.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007196 StackFrameLocator locator;
7197 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007198 ASSERT(Context::cast(frame->context()) == *context);
7199#endif
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007200
7201 // Find where the 'eval' symbol is bound. It is unaliased only if
7202 // it is bound in the global context.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007203 int index = -1;
7204 PropertyAttributes attributes = ABSENT;
7205 while (true) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007206 receiver = context->Lookup(Factory::eval_symbol(), FOLLOW_PROTOTYPE_CHAIN,
7207 &index, &attributes);
iposva@chromium.org245aa852009-02-10 00:49:54 +00007208 // Stop search when eval is found or when the global context is
7209 // reached.
7210 if (attributes != ABSENT || context->IsGlobalContext()) break;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007211 if (context->is_function_context()) {
7212 context = Handle<Context>(Context::cast(context->closure()->context()));
7213 } else {
7214 context = Handle<Context>(context->previous());
7215 }
7216 }
7217
iposva@chromium.org245aa852009-02-10 00:49:54 +00007218 // If eval could not be resolved, it has been deleted and we need to
7219 // throw a reference error.
7220 if (attributes == ABSENT) {
7221 Handle<Object> name = Factory::eval_symbol();
7222 Handle<Object> reference_error =
7223 Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007224 return MakePair(Top::Throw(*reference_error), NULL);
iposva@chromium.org245aa852009-02-10 00:49:54 +00007225 }
7226
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007227 if (!context->IsGlobalContext()) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007228 // 'eval' is not bound in the global context. Just call the function
7229 // with the given arguments. This is not necessarily the global eval.
7230 if (receiver->IsContext()) {
7231 context = Handle<Context>::cast(receiver);
7232 receiver = Handle<Object>(context->get(index));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007233 } else if (receiver->IsJSContextExtensionObject()) {
7234 receiver = Handle<JSObject>(Top::context()->global()->global_receiver());
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007235 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007236 return MakePair(*callee, *receiver);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007237 }
7238
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007239 // 'eval' is bound in the global context, but it may have been overwritten.
7240 // Compare it to the builtin 'GlobalEval' function to make sure.
7241 if (*callee != Top::global_context()->global_eval_fun() ||
7242 !args[1]->IsString()) {
7243 return MakePair(*callee, Top::context()->global()->global_receiver());
7244 }
7245
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00007246 return CompileGlobalEval(args.at<String>(1), args.at<Object>(2));
7247}
7248
7249
7250static ObjectPair Runtime_ResolvePossiblyDirectEvalNoLookup(Arguments args) {
7251 ASSERT(args.length() == 3);
7252 if (!args[0]->IsJSFunction()) {
7253 return MakePair(Top::ThrowIllegalOperation(), NULL);
7254 }
7255
7256 HandleScope scope;
7257 Handle<JSFunction> callee = args.at<JSFunction>(0);
7258
7259 // 'eval' is bound in the global context, but it may have been overwritten.
7260 // Compare it to the builtin 'GlobalEval' function to make sure.
7261 if (*callee != Top::global_context()->global_eval_fun() ||
7262 !args[1]->IsString()) {
7263 return MakePair(*callee, Top::context()->global()->global_receiver());
7264 }
7265
7266 return CompileGlobalEval(args.at<String>(1), args.at<Object>(2));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007267}
7268
7269
lrn@chromium.org303ada72010-10-27 09:33:13 +00007270static MaybeObject* Runtime_SetNewFunctionAttributes(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007271 // This utility adjusts the property attributes for newly created Function
7272 // object ("new Function(...)") by changing the map.
7273 // All it does is changing the prototype property to enumerable
7274 // as specified in ECMA262, 15.3.5.2.
7275 HandleScope scope;
7276 ASSERT(args.length() == 1);
7277 CONVERT_ARG_CHECKED(JSFunction, func, 0);
7278 ASSERT(func->map()->instance_type() ==
7279 Top::function_instance_map()->instance_type());
7280 ASSERT(func->map()->instance_size() ==
7281 Top::function_instance_map()->instance_size());
7282 func->set_map(*Top::function_instance_map());
7283 return *func;
7284}
7285
7286
lrn@chromium.org303ada72010-10-27 09:33:13 +00007287static MaybeObject* Runtime_AllocateInNewSpace(Arguments args) {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00007288 // Allocate a block of memory in NewSpace (filled with a filler).
7289 // Use as fallback for allocation in generated code when NewSpace
7290 // is full.
7291 ASSERT(args.length() == 1);
7292 CONVERT_ARG_CHECKED(Smi, size_smi, 0);
7293 int size = size_smi->value();
7294 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
7295 RUNTIME_ASSERT(size > 0);
7296 static const int kMinFreeNewSpaceAfterGC =
7297 Heap::InitialSemiSpaceSize() * 3/4;
7298 RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007299 Object* allocation;
7300 { MaybeObject* maybe_allocation = Heap::new_space()->AllocateRaw(size);
7301 if (maybe_allocation->ToObject(&allocation)) {
7302 Heap::CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
7303 }
7304 return maybe_allocation;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00007305 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00007306}
7307
7308
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007309// Push an array unto an array of arrays if it is not already in the
7310// array. Returns true if the element was pushed on the stack and
7311// false otherwise.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007312static MaybeObject* Runtime_PushIfAbsent(Arguments args) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007313 ASSERT(args.length() == 2);
7314 CONVERT_CHECKED(JSArray, array, args[0]);
7315 CONVERT_CHECKED(JSArray, element, args[1]);
7316 RUNTIME_ASSERT(array->HasFastElements());
7317 int length = Smi::cast(array->length())->value();
7318 FixedArray* elements = FixedArray::cast(array->elements());
7319 for (int i = 0; i < length; i++) {
7320 if (elements->get(i) == element) return Heap::false_value();
7321 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00007322 Object* obj;
7323 { MaybeObject* maybe_obj = array->SetFastElement(length, element);
7324 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7325 }
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007326 return Heap::true_value();
7327}
7328
7329
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007330/**
7331 * A simple visitor visits every element of Array's.
7332 * The backend storage can be a fixed array for fast elements case,
7333 * or a dictionary for sparse array. Since Dictionary is a subtype
7334 * of FixedArray, the class can be used by both fast and slow cases.
7335 * The second parameter of the constructor, fast_elements, specifies
7336 * whether the storage is a FixedArray or Dictionary.
7337 *
7338 * An index limit is used to deal with the situation that a result array
7339 * length overflows 32-bit non-negative integer.
7340 */
7341class ArrayConcatVisitor {
7342 public:
7343 ArrayConcatVisitor(Handle<FixedArray> storage,
7344 uint32_t index_limit,
7345 bool fast_elements) :
7346 storage_(storage), index_limit_(index_limit),
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007347 index_offset_(0), fast_elements_(fast_elements) { }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007348
7349 void visit(uint32_t i, Handle<Object> elm) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007350 if (i >= index_limit_ - index_offset_) return;
7351 uint32_t index = index_offset_ + i;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007352
7353 if (fast_elements_) {
7354 ASSERT(index < static_cast<uint32_t>(storage_->length()));
7355 storage_->set(index, *elm);
7356
7357 } else {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00007358 Handle<NumberDictionary> dict = Handle<NumberDictionary>::cast(storage_);
7359 Handle<NumberDictionary> result =
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007360 Factory::DictionaryAtNumberPut(dict, index, elm);
7361 if (!result.is_identical_to(dict))
7362 storage_ = result;
7363 }
7364 }
7365
7366 void increase_index_offset(uint32_t delta) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007367 if (index_limit_ - index_offset_ < delta) {
7368 index_offset_ = index_limit_;
7369 } else {
7370 index_offset_ += delta;
7371 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007372 }
7373
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00007374 Handle<FixedArray> storage() { return storage_; }
7375
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007376 private:
7377 Handle<FixedArray> storage_;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007378 // Limit on the accepted indices. Elements with indices larger than the
7379 // limit are ignored by the visitor.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007380 uint32_t index_limit_;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007381 // Index after last seen index. Always less than or equal to index_limit_.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007382 uint32_t index_offset_;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00007383 const bool fast_elements_;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007384};
7385
7386
ager@chromium.org3811b432009-10-28 14:53:37 +00007387template<class ExternalArrayClass, class ElementType>
7388static uint32_t IterateExternalArrayElements(Handle<JSObject> receiver,
7389 bool elements_are_ints,
7390 bool elements_are_guaranteed_smis,
7391 uint32_t range,
7392 ArrayConcatVisitor* visitor) {
7393 Handle<ExternalArrayClass> array(
7394 ExternalArrayClass::cast(receiver->elements()));
7395 uint32_t len = Min(static_cast<uint32_t>(array->length()), range);
7396
7397 if (visitor != NULL) {
7398 if (elements_are_ints) {
7399 if (elements_are_guaranteed_smis) {
7400 for (uint32_t j = 0; j < len; j++) {
7401 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get(j))));
7402 visitor->visit(j, e);
7403 }
7404 } else {
7405 for (uint32_t j = 0; j < len; j++) {
7406 int64_t val = static_cast<int64_t>(array->get(j));
7407 if (Smi::IsValid(static_cast<intptr_t>(val))) {
7408 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
7409 visitor->visit(j, e);
7410 } else {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007411 Handle<Object> e =
7412 Factory::NewNumber(static_cast<ElementType>(val));
ager@chromium.org3811b432009-10-28 14:53:37 +00007413 visitor->visit(j, e);
7414 }
7415 }
7416 }
7417 } else {
7418 for (uint32_t j = 0; j < len; j++) {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007419 Handle<Object> e = Factory::NewNumber(array->get(j));
ager@chromium.org3811b432009-10-28 14:53:37 +00007420 visitor->visit(j, e);
7421 }
7422 }
7423 }
7424
7425 return len;
7426}
7427
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007428/**
7429 * A helper function that visits elements of a JSObject. Only elements
7430 * whose index between 0 and range (exclusive) are visited.
7431 *
7432 * If the third parameter, visitor, is not NULL, the visitor is called
7433 * with parameters, 'visitor_index_offset + element index' and the element.
7434 *
7435 * It returns the number of visisted elements.
7436 */
7437static uint32_t IterateElements(Handle<JSObject> receiver,
7438 uint32_t range,
7439 ArrayConcatVisitor* visitor) {
7440 uint32_t num_of_elements = 0;
7441
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007442 switch (receiver->GetElementsKind()) {
7443 case JSObject::FAST_ELEMENTS: {
7444 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
7445 uint32_t len = elements->length();
7446 if (range < len) {
7447 len = range;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007448 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007449
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007450 for (uint32_t j = 0; j < len; j++) {
7451 Handle<Object> e(elements->get(j));
7452 if (!e->IsTheHole()) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007453 num_of_elements++;
7454 if (visitor) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007455 visitor->visit(j, e);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007456 }
7457 }
7458 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007459 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007460 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007461 case JSObject::PIXEL_ELEMENTS: {
7462 Handle<PixelArray> pixels(PixelArray::cast(receiver->elements()));
7463 uint32_t len = pixels->length();
7464 if (range < len) {
7465 len = range;
7466 }
7467
7468 for (uint32_t j = 0; j < len; j++) {
7469 num_of_elements++;
7470 if (visitor != NULL) {
7471 Handle<Smi> e(Smi::FromInt(pixels->get(j)));
7472 visitor->visit(j, e);
7473 }
7474 }
7475 break;
7476 }
ager@chromium.org3811b432009-10-28 14:53:37 +00007477 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
7478 num_of_elements =
7479 IterateExternalArrayElements<ExternalByteArray, int8_t>(
7480 receiver, true, true, range, visitor);
7481 break;
7482 }
7483 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
7484 num_of_elements =
7485 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
7486 receiver, true, true, range, visitor);
7487 break;
7488 }
7489 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
7490 num_of_elements =
7491 IterateExternalArrayElements<ExternalShortArray, int16_t>(
7492 receiver, true, true, range, visitor);
7493 break;
7494 }
7495 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
7496 num_of_elements =
7497 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
7498 receiver, true, true, range, visitor);
7499 break;
7500 }
7501 case JSObject::EXTERNAL_INT_ELEMENTS: {
7502 num_of_elements =
7503 IterateExternalArrayElements<ExternalIntArray, int32_t>(
7504 receiver, true, false, range, visitor);
7505 break;
7506 }
7507 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
7508 num_of_elements =
7509 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
7510 receiver, true, false, range, visitor);
7511 break;
7512 }
7513 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
7514 num_of_elements =
7515 IterateExternalArrayElements<ExternalFloatArray, float>(
7516 receiver, false, false, range, visitor);
7517 break;
7518 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007519 case JSObject::DICTIONARY_ELEMENTS: {
7520 Handle<NumberDictionary> dict(receiver->element_dictionary());
7521 uint32_t capacity = dict->Capacity();
7522 for (uint32_t j = 0; j < capacity; j++) {
7523 Handle<Object> k(dict->KeyAt(j));
7524 if (dict->IsKey(*k)) {
7525 ASSERT(k->IsNumber());
7526 uint32_t index = static_cast<uint32_t>(k->Number());
7527 if (index < range) {
7528 num_of_elements++;
7529 if (visitor) {
7530 visitor->visit(index, Handle<Object>(dict->ValueAt(j)));
7531 }
7532 }
7533 }
7534 }
7535 break;
7536 }
7537 default:
7538 UNREACHABLE();
7539 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007540 }
7541
7542 return num_of_elements;
7543}
7544
7545
7546/**
7547 * A helper function that visits elements of an Array object, and elements
7548 * on its prototypes.
7549 *
7550 * Elements on prototypes are visited first, and only elements whose indices
7551 * less than Array length are visited.
7552 *
7553 * If a ArrayConcatVisitor object is given, the visitor is called with
7554 * parameters, element's index + visitor_index_offset and the element.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007555 *
7556 * The returned number of elements is an upper bound on the actual number
7557 * of elements added. If the same element occurs in more than one object
7558 * in the array's prototype chain, it will be counted more than once, but
7559 * will only occur once in the result.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007560 */
7561static uint32_t IterateArrayAndPrototypeElements(Handle<JSArray> array,
7562 ArrayConcatVisitor* visitor) {
7563 uint32_t range = static_cast<uint32_t>(array->length()->Number());
7564 Handle<Object> obj = array;
7565
7566 static const int kEstimatedPrototypes = 3;
7567 List< Handle<JSObject> > objects(kEstimatedPrototypes);
7568
7569 // Visit prototype first. If an element on the prototype is shadowed by
7570 // the inheritor using the same index, the ArrayConcatVisitor visits
7571 // the prototype element before the shadowing element.
7572 // The visitor can simply overwrite the old value by new value using
7573 // the same index. This follows Array::concat semantics.
7574 while (!obj->IsNull()) {
7575 objects.Add(Handle<JSObject>::cast(obj));
7576 obj = Handle<Object>(obj->GetPrototype());
7577 }
7578
7579 uint32_t nof_elements = 0;
7580 for (int i = objects.length() - 1; i >= 0; i--) {
7581 Handle<JSObject> obj = objects[i];
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007582 uint32_t encountered_elements =
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007583 IterateElements(Handle<JSObject>::cast(obj), range, visitor);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007584
7585 if (encountered_elements > JSObject::kMaxElementCount - nof_elements) {
7586 nof_elements = JSObject::kMaxElementCount;
7587 } else {
7588 nof_elements += encountered_elements;
7589 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007590 }
7591
7592 return nof_elements;
7593}
7594
7595
7596/**
7597 * A helper function of Runtime_ArrayConcat.
7598 *
7599 * The first argument is an Array of arrays and objects. It is the
7600 * same as the arguments array of Array::concat JS function.
7601 *
7602 * If an argument is an Array object, the function visits array
7603 * elements. If an argument is not an Array object, the function
7604 * visits the object as if it is an one-element array.
7605 *
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007606 * If the result array index overflows 32-bit unsigned integer, the rounded
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007607 * non-negative number is used as new length. For example, if one
7608 * array length is 2^32 - 1, second array length is 1, the
7609 * concatenated array length is 0.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007610 * TODO(lrn) Change length behavior to ECMAScript 5 specification (length
7611 * is one more than the last array index to get a value assigned).
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007612 */
7613static uint32_t IterateArguments(Handle<JSArray> arguments,
7614 ArrayConcatVisitor* visitor) {
7615 uint32_t visited_elements = 0;
7616 uint32_t num_of_args = static_cast<uint32_t>(arguments->length()->Number());
7617
7618 for (uint32_t i = 0; i < num_of_args; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007619 Object *element;
7620 MaybeObject* maybe_element = arguments->GetElement(i);
7621 // This if() is not expected to fail, but we have the check in the
7622 // interest of hardening the runtime calls.
7623 if (maybe_element->ToObject(&element)) {
7624 Handle<Object> obj(element);
7625 if (obj->IsJSArray()) {
7626 Handle<JSArray> array = Handle<JSArray>::cast(obj);
7627 uint32_t len = static_cast<uint32_t>(array->length()->Number());
7628 uint32_t nof_elements =
7629 IterateArrayAndPrototypeElements(array, visitor);
7630 // Total elements of array and its prototype chain can be more than
7631 // the array length, but ArrayConcat can only concatenate at most
7632 // the array length number of elements. We use the length as an estimate
7633 // for the actual number of elements added.
7634 uint32_t added_elements = (nof_elements > len) ? len : nof_elements;
7635 if (JSArray::kMaxElementCount - visited_elements < added_elements) {
7636 visited_elements = JSArray::kMaxElementCount;
7637 } else {
7638 visited_elements += added_elements;
7639 }
7640 if (visitor) visitor->increase_index_offset(len);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007641 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007642 if (visitor) {
7643 visitor->visit(0, obj);
7644 visitor->increase_index_offset(1);
7645 }
7646 if (visited_elements < JSArray::kMaxElementCount) {
7647 visited_elements++;
7648 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007649 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007650 }
7651 }
7652 return visited_elements;
7653}
7654
7655
7656/**
7657 * Array::concat implementation.
7658 * See ECMAScript 262, 15.4.4.4.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007659 * TODO(lrn): Fix non-compliance for very large concatenations and update to
7660 * following the ECMAScript 5 specification.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007661 */
lrn@chromium.org303ada72010-10-27 09:33:13 +00007662static MaybeObject* Runtime_ArrayConcat(Arguments args) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007663 ASSERT(args.length() == 1);
7664 HandleScope handle_scope;
7665
7666 CONVERT_CHECKED(JSArray, arg_arrays, args[0]);
7667 Handle<JSArray> arguments(arg_arrays);
7668
7669 // Pass 1: estimate the number of elements of the result
7670 // (it could be more than real numbers if prototype has elements).
7671 uint32_t result_length = 0;
7672 uint32_t num_of_args = static_cast<uint32_t>(arguments->length()->Number());
7673
7674 { AssertNoAllocation nogc;
7675 for (uint32_t i = 0; i < num_of_args; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007676 Object* obj;
7677 MaybeObject* maybe_object = arguments->GetElement(i);
7678 // This if() is not expected to fail, but we have the check in the
7679 // interest of hardening the runtime calls.
7680 if (maybe_object->ToObject(&obj)) {
7681 uint32_t length_estimate;
7682 if (obj->IsJSArray()) {
7683 length_estimate =
7684 static_cast<uint32_t>(JSArray::cast(obj)->length()->Number());
7685 } else {
7686 length_estimate = 1;
7687 }
7688 if (JSObject::kMaxElementCount - result_length < length_estimate) {
7689 result_length = JSObject::kMaxElementCount;
7690 break;
7691 }
7692 result_length += length_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007693 }
7694 }
7695 }
7696
7697 // Allocate an empty array, will set length and content later.
7698 Handle<JSArray> result = Factory::NewJSArray(0);
7699
7700 uint32_t estimate_nof_elements = IterateArguments(arguments, NULL);
7701 // If estimated number of elements is more than half of length, a
7702 // fixed array (fast case) is more time and space-efficient than a
7703 // dictionary.
7704 bool fast_case = (estimate_nof_elements * 2) >= result_length;
7705
7706 Handle<FixedArray> storage;
7707 if (fast_case) {
7708 // The backing storage array must have non-existing elements to
7709 // preserve holes across concat operations.
7710 storage = Factory::NewFixedArrayWithHoles(result_length);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007711 Handle<Map> fast_map =
7712 Factory::GetFastElementsMap(Handle<Map>(result->map()));
7713 result->set_map(*fast_map);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007714 } else {
7715 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
7716 uint32_t at_least_space_for = estimate_nof_elements +
7717 (estimate_nof_elements >> 2);
7718 storage = Handle<FixedArray>::cast(
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00007719 Factory::NewNumberDictionary(at_least_space_for));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007720 Handle<Map> slow_map =
7721 Factory::GetSlowElementsMap(Handle<Map>(result->map()));
7722 result->set_map(*slow_map);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007723 }
7724
7725 Handle<Object> len = Factory::NewNumber(static_cast<double>(result_length));
7726
7727 ArrayConcatVisitor visitor(storage, result_length, fast_case);
7728
7729 IterateArguments(arguments, &visitor);
7730
7731 result->set_length(*len);
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00007732 // Please note the storage might have changed in the visitor.
7733 result->set_elements(*visitor.storage());
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007734
7735 return *result;
7736}
7737
7738
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007739// This will not allocate (flatten the string), but it may run
7740// very slowly for very deeply nested ConsStrings. For debugging use only.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007741static MaybeObject* Runtime_GlobalPrint(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007742 NoHandleAllocation ha;
7743 ASSERT(args.length() == 1);
7744
7745 CONVERT_CHECKED(String, string, args[0]);
7746 StringInputBuffer buffer(string);
7747 while (buffer.has_more()) {
7748 uint16_t character = buffer.GetNext();
7749 PrintF("%c", character);
7750 }
7751 return string;
7752}
7753
ager@chromium.org5ec48922009-05-05 07:25:34 +00007754// Moves all own elements of an object, that are below a limit, to positions
7755// starting at zero. All undefined values are placed after non-undefined values,
7756// and are followed by non-existing element. Does not change the length
7757// property.
7758// Returns the number of non-undefined elements collected.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007759static MaybeObject* Runtime_RemoveArrayHoles(Arguments args) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00007760 ASSERT(args.length() == 2);
7761 CONVERT_CHECKED(JSObject, object, args[0]);
7762 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
7763 return object->PrepareElementsForSort(limit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007764}
7765
7766
7767// Move contents of argument 0 (an array) to argument 1 (an array)
lrn@chromium.org303ada72010-10-27 09:33:13 +00007768static MaybeObject* Runtime_MoveArrayContents(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007769 ASSERT(args.length() == 2);
7770 CONVERT_CHECKED(JSArray, from, args[0]);
7771 CONVERT_CHECKED(JSArray, to, args[1]);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00007772 HeapObject* new_elements = from->elements();
lrn@chromium.org303ada72010-10-27 09:33:13 +00007773 MaybeObject* maybe_new_map;
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00007774 if (new_elements->map() == Heap::fixed_array_map() ||
7775 new_elements->map() == Heap::fixed_cow_array_map()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007776 maybe_new_map = to->map()->GetFastElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00007777 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007778 maybe_new_map = to->map()->GetSlowElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00007779 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00007780 Object* new_map;
7781 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00007782 to->set_map(Map::cast(new_map));
7783 to->set_elements(new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007784 to->set_length(from->length());
lrn@chromium.org303ada72010-10-27 09:33:13 +00007785 Object* obj;
7786 { MaybeObject* maybe_obj = from->ResetElements();
7787 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7788 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007789 from->set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007790 return to;
7791}
7792
7793
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00007794// How many elements does this object/array have?
lrn@chromium.org303ada72010-10-27 09:33:13 +00007795static MaybeObject* Runtime_EstimateNumberOfElements(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007796 ASSERT(args.length() == 1);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00007797 CONVERT_CHECKED(JSObject, object, args[0]);
7798 HeapObject* elements = object->elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007799 if (elements->IsDictionary()) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00007800 return Smi::FromInt(NumberDictionary::cast(elements)->NumberOfElements());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00007801 } else if (object->IsJSArray()) {
7802 return JSArray::cast(object)->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007803 } else {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00007804 return Smi::FromInt(FixedArray::cast(elements)->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007805 }
7806}
7807
7808
lrn@chromium.org303ada72010-10-27 09:33:13 +00007809static MaybeObject* Runtime_SwapElements(Arguments args) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007810 HandleScope handle_scope;
7811
7812 ASSERT_EQ(3, args.length());
7813
ager@chromium.orgac091b72010-05-05 07:34:42 +00007814 CONVERT_ARG_CHECKED(JSObject, object, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007815 Handle<Object> key1 = args.at<Object>(1);
7816 Handle<Object> key2 = args.at<Object>(2);
7817
7818 uint32_t index1, index2;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007819 if (!key1->ToArrayIndex(&index1)
7820 || !key2->ToArrayIndex(&index2)) {
ager@chromium.orgac091b72010-05-05 07:34:42 +00007821 return Top::ThrowIllegalOperation();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007822 }
7823
ager@chromium.orgac091b72010-05-05 07:34:42 +00007824 Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
7825 Handle<Object> tmp1 = GetElement(jsobject, index1);
7826 Handle<Object> tmp2 = GetElement(jsobject, index2);
7827
7828 SetElement(jsobject, index1, tmp2);
7829 SetElement(jsobject, index2, tmp1);
7830
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007831 return Heap::undefined_value();
7832}
7833
7834
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007835// Returns an array that tells you where in the [0, length) interval an array
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00007836// might have elements. Can either return keys (positive integers) or
7837// intervals (pair of a negative integer (-start-1) followed by a
7838// positive (length)) or undefined values.
7839// Intervals can span over some keys that are not in the object.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007840static MaybeObject* Runtime_GetArrayKeys(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007841 ASSERT(args.length() == 2);
7842 HandleScope scope;
ager@chromium.org5ec48922009-05-05 07:25:34 +00007843 CONVERT_ARG_CHECKED(JSObject, array, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007844 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007845 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007846 // Create an array and get all the keys into it, then remove all the
7847 // keys that are not integers in the range 0 to length-1.
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00007848 Handle<FixedArray> keys = GetKeysInFixedArrayFor(array, INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007849 int keys_length = keys->length();
7850 for (int i = 0; i < keys_length; i++) {
7851 Object* key = keys->get(i);
7852 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007853 if (!key->ToArrayIndex(&index) || index >= length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007854 // Zap invalid keys.
7855 keys->set_undefined(i);
7856 }
7857 }
7858 return *Factory::NewJSArrayWithElements(keys);
7859 } else {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007860 ASSERT(array->HasFastElements());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007861 Handle<FixedArray> single_interval = Factory::NewFixedArray(2);
7862 // -1 means start of array.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007863 single_interval->set(0, Smi::FromInt(-1));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007864 uint32_t actual_length =
7865 static_cast<uint32_t>(FixedArray::cast(array->elements())->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +00007866 uint32_t min_length = actual_length < length ? actual_length : length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007867 Handle<Object> length_object =
ager@chromium.org5ec48922009-05-05 07:25:34 +00007868 Factory::NewNumber(static_cast<double>(min_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007869 single_interval->set(1, *length_object);
7870 return *Factory::NewJSArrayWithElements(single_interval);
7871 }
7872}
7873
7874
7875// DefineAccessor takes an optional final argument which is the
7876// property attributes (eg, DONT_ENUM, DONT_DELETE). IMPORTANT: due
7877// to the way accessors are implemented, it is set for both the getter
7878// and setter on the first call to DefineAccessor and ignored on
7879// subsequent calls.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007880static MaybeObject* Runtime_DefineAccessor(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007881 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
7882 // Compute attributes.
7883 PropertyAttributes attributes = NONE;
7884 if (args.length() == 5) {
7885 CONVERT_CHECKED(Smi, attrs, args[4]);
7886 int value = attrs->value();
7887 // Only attribute bits should be set.
7888 ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
7889 attributes = static_cast<PropertyAttributes>(value);
7890 }
7891
7892 CONVERT_CHECKED(JSObject, obj, args[0]);
7893 CONVERT_CHECKED(String, name, args[1]);
7894 CONVERT_CHECKED(Smi, flag, args[2]);
7895 CONVERT_CHECKED(JSFunction, fun, args[3]);
7896 return obj->DefineAccessor(name, flag->value() == 0, fun, attributes);
7897}
7898
7899
lrn@chromium.org303ada72010-10-27 09:33:13 +00007900static MaybeObject* Runtime_LookupAccessor(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007901 ASSERT(args.length() == 3);
7902 CONVERT_CHECKED(JSObject, obj, args[0]);
7903 CONVERT_CHECKED(String, name, args[1]);
7904 CONVERT_CHECKED(Smi, flag, args[2]);
7905 return obj->LookupAccessor(name, flag->value() == 0);
7906}
7907
7908
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007909#ifdef ENABLE_DEBUGGER_SUPPORT
lrn@chromium.org303ada72010-10-27 09:33:13 +00007910static MaybeObject* Runtime_DebugBreak(Arguments args) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007911 ASSERT(args.length() == 0);
7912 return Execution::DebugBreakHelper();
7913}
7914
7915
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007916// Helper functions for wrapping and unwrapping stack frame ids.
7917static Smi* WrapFrameId(StackFrame::Id id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +00007918 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007919 return Smi::FromInt(id >> 2);
7920}
7921
7922
7923static StackFrame::Id UnwrapFrameId(Smi* wrapped) {
7924 return static_cast<StackFrame::Id>(wrapped->value() << 2);
7925}
7926
7927
7928// Adds a JavaScript function as a debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +00007929// args[0]: debug event listener function to set or null or undefined for
7930// clearing the event listener function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007931// args[1]: object supplied during callback
lrn@chromium.org303ada72010-10-27 09:33:13 +00007932static MaybeObject* Runtime_SetDebugEventListener(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007933 ASSERT(args.length() == 2);
iposva@chromium.org245aa852009-02-10 00:49:54 +00007934 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
7935 args[0]->IsUndefined() ||
7936 args[0]->IsNull());
7937 Handle<Object> callback = args.at<Object>(0);
7938 Handle<Object> data = args.at<Object>(1);
7939 Debugger::SetEventListener(callback, data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007940
7941 return Heap::undefined_value();
7942}
7943
7944
lrn@chromium.org303ada72010-10-27 09:33:13 +00007945static MaybeObject* Runtime_Break(Arguments args) {
mads.s.ager31e71382008-08-13 09:32:07 +00007946 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007947 StackGuard::DebugBreak();
7948 return Heap::undefined_value();
7949}
7950
7951
lrn@chromium.org303ada72010-10-27 09:33:13 +00007952static MaybeObject* DebugLookupResultValue(Object* receiver, String* name,
7953 LookupResult* result,
7954 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00007955 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007956 switch (result->type()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007957 case NORMAL:
7958 value = result->holder()->GetNormalizedProperty(result);
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00007959 if (value->IsTheHole()) {
7960 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007961 }
7962 return value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00007963 case FIELD:
7964 value =
7965 JSObject::cast(
7966 result->holder())->FastPropertyAt(result->GetFieldIndex());
7967 if (value->IsTheHole()) {
7968 return Heap::undefined_value();
7969 }
7970 return value;
7971 case CONSTANT_FUNCTION:
7972 return result->GetConstantFunction();
7973 case CALLBACKS: {
7974 Object* structure = result->GetCallbackObject();
kasperl@chromium.org71affb52009-05-26 05:44:31 +00007975 if (structure->IsProxy() || structure->IsAccessorInfo()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007976 MaybeObject* maybe_value = receiver->GetPropertyWithCallback(
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00007977 receiver, structure, name, result->holder());
lrn@chromium.org303ada72010-10-27 09:33:13 +00007978 if (!maybe_value->ToObject(&value)) {
7979 ASSERT(maybe_value->IsException());
7980 maybe_value = Top::pending_exception();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00007981 Top::clear_pending_exception();
7982 if (caught_exception != NULL) {
7983 *caught_exception = true;
7984 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00007985 return maybe_value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00007986 }
7987 return value;
7988 } else {
7989 return Heap::undefined_value();
7990 }
7991 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007992 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007993 case MAP_TRANSITION:
7994 case CONSTANT_TRANSITION:
7995 case NULL_DESCRIPTOR:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007996 return Heap::undefined_value();
7997 default:
7998 UNREACHABLE();
7999 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008000 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008001 return Heap::undefined_value();
8002}
8003
8004
ager@chromium.org32912102009-01-16 10:38:43 +00008005// Get debugger related details for an object property.
8006// args[0]: object holding property
8007// args[1]: name of the property
8008//
8009// The array returned contains the following information:
8010// 0: Property value
8011// 1: Property details
8012// 2: Property value is exception
8013// 3: Getter function if defined
8014// 4: Setter function if defined
8015// Items 2-4 are only filled if the property has either a getter or a setter
8016// defined through __defineGetter__ and/or __defineSetter__.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008017static MaybeObject* Runtime_DebugGetPropertyDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008018 HandleScope scope;
8019
8020 ASSERT(args.length() == 2);
8021
8022 CONVERT_ARG_CHECKED(JSObject, obj, 0);
8023 CONVERT_ARG_CHECKED(String, name, 1);
8024
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00008025 // Make sure to set the current context to the context before the debugger was
8026 // entered (if the debugger is entered). The reason for switching context here
8027 // is that for some property lookups (accessors and interceptors) callbacks
8028 // into the embedding application can occour, and the embedding application
8029 // could have the assumption that its own global context is the current
8030 // context and not some internal debugger context.
8031 SaveContext save;
8032 if (Debug::InDebugger()) {
8033 Top::set_context(*Debug::debugger_entry()->GetContext());
8034 }
8035
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008036 // Skip the global proxy as it has no properties and always delegates to the
8037 // real global object.
8038 if (obj->IsJSGlobalProxy()) {
8039 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
8040 }
8041
8042
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008043 // Check if the name is trivially convertible to an index and get the element
8044 // if so.
8045 uint32_t index;
8046 if (name->AsArrayIndex(&index)) {
8047 Handle<FixedArray> details = Factory::NewFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008048 Object* element_or_char;
8049 { MaybeObject* maybe_element_or_char =
8050 Runtime::GetElementOrCharAt(obj, index);
8051 if (!maybe_element_or_char->ToObject(&element_or_char)) {
8052 return maybe_element_or_char;
8053 }
8054 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008055 details->set(0, element_or_char);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008056 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
8057 return *Factory::NewJSArrayWithElements(details);
8058 }
8059
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008060 // Find the number of objects making up this.
8061 int length = LocalPrototypeChainLength(*obj);
8062
8063 // Try local lookup on each of the objects.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008064 Handle<JSObject> jsproto = obj;
8065 for (int i = 0; i < length; i++) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008066 LookupResult result;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008067 jsproto->LocalLookup(*name, &result);
8068 if (result.IsProperty()) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008069 // LookupResult is not GC safe as it holds raw object pointers.
8070 // GC can happen later in this code so put the required fields into
8071 // local variables using handles when required for later use.
8072 PropertyType result_type = result.type();
8073 Handle<Object> result_callback_obj;
8074 if (result_type == CALLBACKS) {
8075 result_callback_obj = Handle<Object>(result.GetCallbackObject());
8076 }
8077 Smi* property_details = result.GetPropertyDetails().AsSmi();
8078 // DebugLookupResultValue can cause GC so details from LookupResult needs
8079 // to be copied to handles before this.
8080 bool caught_exception = false;
lrn@chromium.org303ada72010-10-27 09:33:13 +00008081 Object* raw_value;
8082 { MaybeObject* maybe_raw_value =
8083 DebugLookupResultValue(*obj, *name, &result, &caught_exception);
8084 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
8085 }
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008086 Handle<Object> value(raw_value);
8087
8088 // If the callback object is a fixed array then it contains JavaScript
8089 // getter and/or setter.
8090 bool hasJavaScriptAccessors = result_type == CALLBACKS &&
8091 result_callback_obj->IsFixedArray();
8092 Handle<FixedArray> details =
8093 Factory::NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
8094 details->set(0, *value);
8095 details->set(1, property_details);
8096 if (hasJavaScriptAccessors) {
8097 details->set(2,
8098 caught_exception ? Heap::true_value()
8099 : Heap::false_value());
8100 details->set(3, FixedArray::cast(*result_callback_obj)->get(0));
8101 details->set(4, FixedArray::cast(*result_callback_obj)->get(1));
8102 }
8103
8104 return *Factory::NewJSArrayWithElements(details);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008105 }
8106 if (i < length - 1) {
8107 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
8108 }
8109 }
8110
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008111 return Heap::undefined_value();
8112}
8113
8114
lrn@chromium.org303ada72010-10-27 09:33:13 +00008115static MaybeObject* Runtime_DebugGetProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008116 HandleScope scope;
8117
8118 ASSERT(args.length() == 2);
8119
8120 CONVERT_ARG_CHECKED(JSObject, obj, 0);
8121 CONVERT_ARG_CHECKED(String, name, 1);
8122
8123 LookupResult result;
8124 obj->Lookup(*name, &result);
8125 if (result.IsProperty()) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +00008126 return DebugLookupResultValue(*obj, *name, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008127 }
8128 return Heap::undefined_value();
8129}
8130
8131
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008132// Return the property type calculated from the property details.
8133// args[0]: smi with property details.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008134static MaybeObject* Runtime_DebugPropertyTypeFromDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008135 ASSERT(args.length() == 1);
8136 CONVERT_CHECKED(Smi, details, args[0]);
8137 PropertyType type = PropertyDetails(details).type();
8138 return Smi::FromInt(static_cast<int>(type));
8139}
8140
8141
8142// Return the property attribute calculated from the property details.
8143// args[0]: smi with property details.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008144static MaybeObject* Runtime_DebugPropertyAttributesFromDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008145 ASSERT(args.length() == 1);
8146 CONVERT_CHECKED(Smi, details, args[0]);
8147 PropertyAttributes attributes = PropertyDetails(details).attributes();
8148 return Smi::FromInt(static_cast<int>(attributes));
8149}
8150
8151
8152// Return the property insertion index calculated from the property details.
8153// args[0]: smi with property details.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008154static MaybeObject* Runtime_DebugPropertyIndexFromDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008155 ASSERT(args.length() == 1);
8156 CONVERT_CHECKED(Smi, details, args[0]);
8157 int index = PropertyDetails(details).index();
8158 return Smi::FromInt(index);
8159}
8160
8161
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008162// Return property value from named interceptor.
8163// args[0]: object
8164// args[1]: property name
lrn@chromium.org303ada72010-10-27 09:33:13 +00008165static MaybeObject* Runtime_DebugNamedInterceptorPropertyValue(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008166 HandleScope scope;
8167 ASSERT(args.length() == 2);
8168 CONVERT_ARG_CHECKED(JSObject, obj, 0);
8169 RUNTIME_ASSERT(obj->HasNamedInterceptor());
8170 CONVERT_ARG_CHECKED(String, name, 1);
8171
8172 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008173 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008174}
8175
8176
8177// Return element value from indexed interceptor.
8178// args[0]: object
8179// args[1]: index
lrn@chromium.org303ada72010-10-27 09:33:13 +00008180static MaybeObject* Runtime_DebugIndexedInterceptorElementValue(
8181 Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008182 HandleScope scope;
8183 ASSERT(args.length() == 2);
8184 CONVERT_ARG_CHECKED(JSObject, obj, 0);
8185 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
8186 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
8187
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008188 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008189}
8190
8191
lrn@chromium.org303ada72010-10-27 09:33:13 +00008192static MaybeObject* Runtime_CheckExecutionState(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008193 ASSERT(args.length() >= 1);
8194 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +00008195 // Check that the break id is valid.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00008196 if (Debug::break_id() == 0 || break_id != Debug::break_id()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008197 return Top::Throw(Heap::illegal_execution_state_symbol());
8198 }
8199
8200 return Heap::true_value();
8201}
8202
8203
lrn@chromium.org303ada72010-10-27 09:33:13 +00008204static MaybeObject* Runtime_GetFrameCount(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008205 HandleScope scope;
8206 ASSERT(args.length() == 1);
8207
8208 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008209 Object* result;
8210 { MaybeObject* maybe_result = Runtime_CheckExecutionState(args);
8211 if (!maybe_result->ToObject(&result)) return maybe_result;
8212 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008213
8214 // Count all frames which are relevant to debugging stack trace.
8215 int n = 0;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00008216 StackFrame::Id id = Debug::break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00008217 if (id == StackFrame::NO_ID) {
8218 // If there is no JavaScript stack frame count is 0.
8219 return Smi::FromInt(0);
8220 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008221 for (JavaScriptFrameIterator it(id); !it.done(); it.Advance()) n++;
8222 return Smi::FromInt(n);
8223}
8224
8225
8226static const int kFrameDetailsFrameIdIndex = 0;
8227static const int kFrameDetailsReceiverIndex = 1;
8228static const int kFrameDetailsFunctionIndex = 2;
8229static const int kFrameDetailsArgumentCountIndex = 3;
8230static const int kFrameDetailsLocalCountIndex = 4;
8231static const int kFrameDetailsSourcePositionIndex = 5;
8232static const int kFrameDetailsConstructCallIndex = 6;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008233static const int kFrameDetailsAtReturnIndex = 7;
8234static const int kFrameDetailsDebuggerFrameIndex = 8;
8235static const int kFrameDetailsFirstDynamicIndex = 9;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008236
8237// Return an array with frame details
8238// args[0]: number: break id
8239// args[1]: number: frame index
8240//
8241// The array returned contains the following information:
8242// 0: Frame id
8243// 1: Receiver
8244// 2: Function
8245// 3: Argument count
8246// 4: Local count
8247// 5: Source position
8248// 6: Constructor call
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008249// 7: Is at return
8250// 8: Debugger frame
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008251// Arguments name, value
8252// Locals name, value
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008253// Return value if any
lrn@chromium.org303ada72010-10-27 09:33:13 +00008254static MaybeObject* Runtime_GetFrameDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008255 HandleScope scope;
8256 ASSERT(args.length() == 2);
8257
8258 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008259 Object* check;
8260 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
8261 if (!maybe_check->ToObject(&check)) return maybe_check;
8262 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008263 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
8264
8265 // Find the relevant frame with the requested index.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00008266 StackFrame::Id id = Debug::break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00008267 if (id == StackFrame::NO_ID) {
8268 // If there are no JavaScript stack frames return undefined.
8269 return Heap::undefined_value();
8270 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008271 int count = 0;
8272 JavaScriptFrameIterator it(id);
8273 for (; !it.done(); it.Advance()) {
8274 if (count == index) break;
8275 count++;
8276 }
8277 if (it.done()) return Heap::undefined_value();
8278
8279 // Traverse the saved contexts chain to find the active context for the
8280 // selected frame.
8281 SaveContext* save = Top::save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008282 while (save != NULL && !save->below(it.frame())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008283 save = save->prev();
8284 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008285 ASSERT(save != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008286
8287 // Get the frame id.
8288 Handle<Object> frame_id(WrapFrameId(it.frame()->id()));
8289
8290 // Find source position.
kasperl@chromium.org061ef742009-02-27 12:16:20 +00008291 int position = it.frame()->code()->SourcePosition(it.frame()->pc());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008292
8293 // Check for constructor frame.
8294 bool constructor = it.frame()->IsConstructor();
8295
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00008296 // Get scope info and read from it for local variable information.
8297 Handle<JSFunction> function(JSFunction::cast(it.frame()->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +00008298 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00008299 ScopeInfo<> info(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008300
8301 // Get the context.
8302 Handle<Context> context(Context::cast(it.frame()->context()));
8303
8304 // Get the locals names and values into a temporary array.
8305 //
8306 // TODO(1240907): Hide compiler-introduced stack variables
8307 // (e.g. .result)? For users of the debugger, they will probably be
8308 // confusing.
8309 Handle<FixedArray> locals = Factory::NewFixedArray(info.NumberOfLocals() * 2);
8310 for (int i = 0; i < info.NumberOfLocals(); i++) {
8311 // Name of the local.
8312 locals->set(i * 2, *info.LocalName(i));
8313
8314 // Fetch the value of the local - either from the stack or from a
8315 // heap-allocated context.
8316 if (i < info.number_of_stack_slots()) {
8317 locals->set(i * 2 + 1, it.frame()->GetExpression(i));
8318 } else {
8319 Handle<String> name = info.LocalName(i);
8320 // Traverse the context chain to the function context as all local
8321 // variables stored in the context will be on the function context.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008322 while (!context->is_function_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008323 context = Handle<Context>(context->previous());
8324 }
8325 ASSERT(context->is_function_context());
8326 locals->set(i * 2 + 1,
ager@chromium.orgb5737492010-07-15 09:29:43 +00008327 context->get(scope_info->ContextSlotIndex(*name, NULL)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008328 }
8329 }
8330
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008331 // Check whether this frame is positioned at return.
8332 int at_return = (index == 0) ? Debug::IsBreakAtReturn(it.frame()) : false;
8333
8334 // If positioned just before return find the value to be returned and add it
8335 // to the frame information.
8336 Handle<Object> return_value = Factory::undefined_value();
8337 if (at_return) {
8338 StackFrameIterator it2;
8339 Address internal_frame_sp = NULL;
8340 while (!it2.done()) {
8341 if (it2.frame()->is_internal()) {
8342 internal_frame_sp = it2.frame()->sp();
8343 } else {
8344 if (it2.frame()->is_java_script()) {
8345 if (it2.frame()->id() == it.frame()->id()) {
8346 // The internal frame just before the JavaScript frame contains the
8347 // value to return on top. A debug break at return will create an
8348 // internal frame to store the return value (eax/rax/r0) before
8349 // entering the debug break exit frame.
8350 if (internal_frame_sp != NULL) {
8351 return_value =
8352 Handle<Object>(Memory::Object_at(internal_frame_sp));
8353 break;
8354 }
8355 }
8356 }
8357
8358 // Indicate that the previous frame was not an internal frame.
8359 internal_frame_sp = NULL;
8360 }
8361 it2.Advance();
8362 }
8363 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008364
8365 // Now advance to the arguments adapter frame (if any). It contains all
8366 // the provided parameters whereas the function frame always have the number
8367 // of arguments matching the functions parameters. The rest of the
8368 // information (except for what is collected above) is the same.
8369 it.AdvanceToArgumentsFrame();
8370
8371 // Find the number of arguments to fill. At least fill the number of
8372 // parameters for the function and fill more if more parameters are provided.
8373 int argument_count = info.number_of_parameters();
8374 if (argument_count < it.frame()->GetProvidedParametersCount()) {
8375 argument_count = it.frame()->GetProvidedParametersCount();
8376 }
8377
8378 // Calculate the size of the result.
8379 int details_size = kFrameDetailsFirstDynamicIndex +
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008380 2 * (argument_count + info.NumberOfLocals()) +
8381 (at_return ? 1 : 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008382 Handle<FixedArray> details = Factory::NewFixedArray(details_size);
8383
8384 // Add the frame id.
8385 details->set(kFrameDetailsFrameIdIndex, *frame_id);
8386
8387 // Add the function (same as in function frame).
8388 details->set(kFrameDetailsFunctionIndex, it.frame()->function());
8389
8390 // Add the arguments count.
8391 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
8392
8393 // Add the locals count
8394 details->set(kFrameDetailsLocalCountIndex,
8395 Smi::FromInt(info.NumberOfLocals()));
8396
8397 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +00008398 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008399 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
8400 } else {
8401 details->set(kFrameDetailsSourcePositionIndex, Heap::undefined_value());
8402 }
8403
8404 // Add the constructor information.
8405 details->set(kFrameDetailsConstructCallIndex, Heap::ToBoolean(constructor));
8406
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008407 // Add the at return information.
8408 details->set(kFrameDetailsAtReturnIndex, Heap::ToBoolean(at_return));
8409
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008410 // Add information on whether this frame is invoked in the debugger context.
8411 details->set(kFrameDetailsDebuggerFrameIndex,
8412 Heap::ToBoolean(*save->context() == *Debug::debug_context()));
8413
8414 // Fill the dynamic part.
8415 int details_index = kFrameDetailsFirstDynamicIndex;
8416
8417 // Add arguments name and value.
8418 for (int i = 0; i < argument_count; i++) {
8419 // Name of the argument.
8420 if (i < info.number_of_parameters()) {
8421 details->set(details_index++, *info.parameter_name(i));
8422 } else {
8423 details->set(details_index++, Heap::undefined_value());
8424 }
8425
8426 // Parameter value.
8427 if (i < it.frame()->GetProvidedParametersCount()) {
8428 details->set(details_index++, it.frame()->GetParameter(i));
8429 } else {
8430 details->set(details_index++, Heap::undefined_value());
8431 }
8432 }
8433
8434 // Add locals name and value from the temporary copy from the function frame.
8435 for (int i = 0; i < info.NumberOfLocals() * 2; i++) {
8436 details->set(details_index++, locals->get(i));
8437 }
8438
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008439 // Add the value being returned.
8440 if (at_return) {
8441 details->set(details_index++, *return_value);
8442 }
8443
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008444 // Add the receiver (same as in function frame).
8445 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
8446 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
8447 Handle<Object> receiver(it.frame()->receiver());
8448 if (!receiver->IsJSObject()) {
8449 // If the receiver is NOT a JSObject we have hit an optimization
8450 // where a value object is not converted into a wrapped JS objects.
8451 // To hide this optimization from the debugger, we wrap the receiver
8452 // by creating correct wrapper object based on the calling frame's
8453 // global context.
8454 it.Advance();
8455 Handle<Context> calling_frames_global_context(
8456 Context::cast(Context::cast(it.frame()->context())->global_context()));
8457 receiver = Factory::ToObject(receiver, calling_frames_global_context);
8458 }
8459 details->set(kFrameDetailsReceiverIndex, *receiver);
8460
8461 ASSERT_EQ(details_size, details_index);
8462 return *Factory::NewJSArrayWithElements(details);
8463}
8464
8465
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008466// Copy all the context locals into an object used to materialize a scope.
ager@chromium.orgb5737492010-07-15 09:29:43 +00008467static void CopyContextLocalsToScopeObject(
8468 Handle<SerializedScopeInfo> serialized_scope_info,
8469 ScopeInfo<>& scope_info,
8470 Handle<Context> context,
8471 Handle<JSObject> scope_object) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008472 // Fill all context locals to the context extension.
8473 for (int i = Context::MIN_CONTEXT_SLOTS;
8474 i < scope_info.number_of_context_slots();
8475 i++) {
ager@chromium.orgb5737492010-07-15 09:29:43 +00008476 int context_index = serialized_scope_info->ContextSlotIndex(
8477 *scope_info.context_slot_name(i), NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008478
8479 // Don't include the arguments shadow (.arguments) context variable.
8480 if (*scope_info.context_slot_name(i) != Heap::arguments_shadow_symbol()) {
8481 SetProperty(scope_object,
8482 scope_info.context_slot_name(i),
8483 Handle<Object>(context->get(context_index)), NONE);
8484 }
8485 }
8486}
8487
8488
8489// Create a plain JSObject which materializes the local scope for the specified
8490// frame.
8491static Handle<JSObject> MaterializeLocalScope(JavaScriptFrame* frame) {
8492 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00008493 Handle<SharedFunctionInfo> shared(function->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +00008494 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
8495 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008496
8497 // Allocate and initialize a JSObject with all the arguments, stack locals
8498 // heap locals and extension properties of the debugged function.
8499 Handle<JSObject> local_scope = Factory::NewJSObject(Top::object_function());
8500
8501 // First fill all parameters.
8502 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
8503 SetProperty(local_scope,
8504 scope_info.parameter_name(i),
8505 Handle<Object>(frame->GetParameter(i)), NONE);
8506 }
8507
8508 // Second fill all stack locals.
8509 for (int i = 0; i < scope_info.number_of_stack_slots(); i++) {
8510 SetProperty(local_scope,
8511 scope_info.stack_slot_name(i),
8512 Handle<Object>(frame->GetExpression(i)), NONE);
8513 }
8514
8515 // Third fill all context locals.
8516 Handle<Context> frame_context(Context::cast(frame->context()));
8517 Handle<Context> function_context(frame_context->fcontext());
ager@chromium.orgb5737492010-07-15 09:29:43 +00008518 CopyContextLocalsToScopeObject(serialized_scope_info, scope_info,
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008519 function_context, local_scope);
8520
8521 // Finally copy any properties from the function context extension. This will
8522 // be variables introduced by eval.
8523 if (function_context->closure() == *function) {
8524 if (function_context->has_extension() &&
8525 !function_context->IsGlobalContext()) {
8526 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008527 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008528 for (int i = 0; i < keys->length(); i++) {
8529 // Names of variables introduced by eval are strings.
8530 ASSERT(keys->get(i)->IsString());
8531 Handle<String> key(String::cast(keys->get(i)));
8532 SetProperty(local_scope, key, GetProperty(ext, key), NONE);
8533 }
8534 }
8535 }
8536 return local_scope;
8537}
8538
8539
8540// Create a plain JSObject which materializes the closure content for the
8541// context.
8542static Handle<JSObject> MaterializeClosure(Handle<Context> context) {
8543 ASSERT(context->is_function_context());
8544
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00008545 Handle<SharedFunctionInfo> shared(context->closure()->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +00008546 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
8547 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008548
8549 // Allocate and initialize a JSObject with all the content of theis function
8550 // closure.
8551 Handle<JSObject> closure_scope = Factory::NewJSObject(Top::object_function());
8552
8553 // Check whether the arguments shadow object exists.
8554 int arguments_shadow_index =
ager@chromium.orgb5737492010-07-15 09:29:43 +00008555 shared->scope_info()->ContextSlotIndex(Heap::arguments_shadow_symbol(),
8556 NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008557 if (arguments_shadow_index >= 0) {
8558 // In this case all the arguments are available in the arguments shadow
8559 // object.
8560 Handle<JSObject> arguments_shadow(
8561 JSObject::cast(context->get(arguments_shadow_index)));
8562 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008563 // We don't expect exception-throwing getters on the arguments shadow.
8564 Object* element = arguments_shadow->GetElement(i)->ToObjectUnchecked();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008565 SetProperty(closure_scope,
8566 scope_info.parameter_name(i),
lrn@chromium.org303ada72010-10-27 09:33:13 +00008567 Handle<Object>(element),
8568 NONE);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008569 }
8570 }
8571
8572 // Fill all context locals to the context extension.
ager@chromium.orgb5737492010-07-15 09:29:43 +00008573 CopyContextLocalsToScopeObject(serialized_scope_info, scope_info,
8574 context, closure_scope);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008575
8576 // Finally copy any properties from the function context extension. This will
8577 // be variables introduced by eval.
8578 if (context->has_extension()) {
8579 Handle<JSObject> ext(JSObject::cast(context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008580 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008581 for (int i = 0; i < keys->length(); i++) {
8582 // Names of variables introduced by eval are strings.
8583 ASSERT(keys->get(i)->IsString());
8584 Handle<String> key(String::cast(keys->get(i)));
8585 SetProperty(closure_scope, key, GetProperty(ext, key), NONE);
8586 }
8587 }
8588
8589 return closure_scope;
8590}
8591
8592
8593// Iterate over the actual scopes visible from a stack frame. All scopes are
8594// backed by an actual context except the local scope, which is inserted
8595// "artifically" in the context chain.
8596class ScopeIterator {
8597 public:
8598 enum ScopeType {
8599 ScopeTypeGlobal = 0,
8600 ScopeTypeLocal,
8601 ScopeTypeWith,
ager@chromium.orga1645e22009-09-09 19:27:10 +00008602 ScopeTypeClosure,
8603 // Every catch block contains an implicit with block (its parameter is
8604 // a JSContextExtensionObject) that extends current scope with a variable
8605 // holding exception object. Such with blocks are treated as scopes of their
8606 // own type.
8607 ScopeTypeCatch
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008608 };
8609
8610 explicit ScopeIterator(JavaScriptFrame* frame)
8611 : frame_(frame),
8612 function_(JSFunction::cast(frame->function())),
8613 context_(Context::cast(frame->context())),
8614 local_done_(false),
8615 at_local_(false) {
8616
8617 // Check whether the first scope is actually a local scope.
8618 if (context_->IsGlobalContext()) {
8619 // If there is a stack slot for .result then this local scope has been
8620 // created for evaluating top level code and it is not a real local scope.
8621 // Checking for the existence of .result seems fragile, but the scope info
8622 // saved with the code object does not otherwise have that information.
ager@chromium.orgb5737492010-07-15 09:29:43 +00008623 int index = function_->shared()->scope_info()->
8624 StackSlotIndex(Heap::result_symbol());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008625 at_local_ = index < 0;
8626 } else if (context_->is_function_context()) {
8627 at_local_ = true;
8628 }
8629 }
8630
8631 // More scopes?
8632 bool Done() { return context_.is_null(); }
8633
8634 // Move to the next scope.
8635 void Next() {
8636 // If at a local scope mark the local scope as passed.
8637 if (at_local_) {
8638 at_local_ = false;
8639 local_done_ = true;
8640
8641 // If the current context is not associated with the local scope the
8642 // current context is the next real scope, so don't move to the next
8643 // context in this case.
8644 if (context_->closure() != *function_) {
8645 return;
8646 }
8647 }
8648
8649 // The global scope is always the last in the chain.
8650 if (context_->IsGlobalContext()) {
8651 context_ = Handle<Context>();
8652 return;
8653 }
8654
8655 // Move to the next context.
8656 if (context_->is_function_context()) {
8657 context_ = Handle<Context>(Context::cast(context_->closure()->context()));
8658 } else {
8659 context_ = Handle<Context>(context_->previous());
8660 }
8661
8662 // If passing the local scope indicate that the current scope is now the
8663 // local scope.
8664 if (!local_done_ &&
8665 (context_->IsGlobalContext() || (context_->is_function_context()))) {
8666 at_local_ = true;
8667 }
8668 }
8669
8670 // Return the type of the current scope.
8671 int Type() {
8672 if (at_local_) {
8673 return ScopeTypeLocal;
8674 }
8675 if (context_->IsGlobalContext()) {
8676 ASSERT(context_->global()->IsGlobalObject());
8677 return ScopeTypeGlobal;
8678 }
8679 if (context_->is_function_context()) {
8680 return ScopeTypeClosure;
8681 }
8682 ASSERT(context_->has_extension());
ager@chromium.orga1645e22009-09-09 19:27:10 +00008683 // Current scope is either an explicit with statement or a with statement
8684 // implicitely generated for a catch block.
8685 // If the extension object here is a JSContextExtensionObject then
8686 // current with statement is one frome a catch block otherwise it's a
8687 // regular with statement.
8688 if (context_->extension()->IsJSContextExtensionObject()) {
8689 return ScopeTypeCatch;
8690 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008691 return ScopeTypeWith;
8692 }
8693
8694 // Return the JavaScript object with the content of the current scope.
8695 Handle<JSObject> ScopeObject() {
8696 switch (Type()) {
8697 case ScopeIterator::ScopeTypeGlobal:
8698 return Handle<JSObject>(CurrentContext()->global());
8699 break;
8700 case ScopeIterator::ScopeTypeLocal:
8701 // Materialize the content of the local scope into a JSObject.
8702 return MaterializeLocalScope(frame_);
8703 break;
8704 case ScopeIterator::ScopeTypeWith:
ager@chromium.orga1645e22009-09-09 19:27:10 +00008705 case ScopeIterator::ScopeTypeCatch:
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008706 // Return the with object.
8707 return Handle<JSObject>(CurrentContext()->extension());
8708 break;
8709 case ScopeIterator::ScopeTypeClosure:
8710 // Materialize the content of the closure scope into a JSObject.
8711 return MaterializeClosure(CurrentContext());
8712 break;
8713 }
8714 UNREACHABLE();
8715 return Handle<JSObject>();
8716 }
8717
8718 // Return the context for this scope. For the local context there might not
8719 // be an actual context.
8720 Handle<Context> CurrentContext() {
8721 if (at_local_ && context_->closure() != *function_) {
8722 return Handle<Context>();
8723 }
8724 return context_;
8725 }
8726
8727#ifdef DEBUG
8728 // Debug print of the content of the current scope.
8729 void DebugPrint() {
8730 switch (Type()) {
8731 case ScopeIterator::ScopeTypeGlobal:
8732 PrintF("Global:\n");
8733 CurrentContext()->Print();
8734 break;
8735
8736 case ScopeIterator::ScopeTypeLocal: {
8737 PrintF("Local:\n");
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00008738 ScopeInfo<> scope_info(function_->shared()->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008739 scope_info.Print();
8740 if (!CurrentContext().is_null()) {
8741 CurrentContext()->Print();
8742 if (CurrentContext()->has_extension()) {
8743 Handle<JSObject> extension =
8744 Handle<JSObject>(CurrentContext()->extension());
8745 if (extension->IsJSContextExtensionObject()) {
8746 extension->Print();
8747 }
8748 }
8749 }
8750 break;
8751 }
8752
8753 case ScopeIterator::ScopeTypeWith: {
8754 PrintF("With:\n");
8755 Handle<JSObject> extension =
8756 Handle<JSObject>(CurrentContext()->extension());
8757 extension->Print();
8758 break;
8759 }
8760
ager@chromium.orga1645e22009-09-09 19:27:10 +00008761 case ScopeIterator::ScopeTypeCatch: {
8762 PrintF("Catch:\n");
8763 Handle<JSObject> extension =
8764 Handle<JSObject>(CurrentContext()->extension());
8765 extension->Print();
8766 break;
8767 }
8768
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008769 case ScopeIterator::ScopeTypeClosure: {
8770 PrintF("Closure:\n");
8771 CurrentContext()->Print();
8772 if (CurrentContext()->has_extension()) {
8773 Handle<JSObject> extension =
8774 Handle<JSObject>(CurrentContext()->extension());
8775 if (extension->IsJSContextExtensionObject()) {
8776 extension->Print();
8777 }
8778 }
8779 break;
8780 }
8781
8782 default:
8783 UNREACHABLE();
8784 }
8785 PrintF("\n");
8786 }
8787#endif
8788
8789 private:
8790 JavaScriptFrame* frame_;
8791 Handle<JSFunction> function_;
8792 Handle<Context> context_;
8793 bool local_done_;
8794 bool at_local_;
8795
8796 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
8797};
8798
8799
lrn@chromium.org303ada72010-10-27 09:33:13 +00008800static MaybeObject* Runtime_GetScopeCount(Arguments args) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008801 HandleScope scope;
8802 ASSERT(args.length() == 2);
8803
8804 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008805 Object* check;
8806 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
8807 if (!maybe_check->ToObject(&check)) return maybe_check;
8808 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008809 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
8810
8811 // Get the frame where the debugging is performed.
8812 StackFrame::Id id = UnwrapFrameId(wrapped_id);
8813 JavaScriptFrameIterator it(id);
8814 JavaScriptFrame* frame = it.frame();
8815
8816 // Count the visible scopes.
8817 int n = 0;
8818 for (ScopeIterator it(frame); !it.Done(); it.Next()) {
8819 n++;
8820 }
8821
8822 return Smi::FromInt(n);
8823}
8824
8825
8826static const int kScopeDetailsTypeIndex = 0;
8827static const int kScopeDetailsObjectIndex = 1;
8828static const int kScopeDetailsSize = 2;
8829
8830// Return an array with scope details
8831// args[0]: number: break id
8832// args[1]: number: frame index
8833// args[2]: number: scope index
8834//
8835// The array returned contains the following information:
8836// 0: Scope type
8837// 1: Scope object
lrn@chromium.org303ada72010-10-27 09:33:13 +00008838static MaybeObject* Runtime_GetScopeDetails(Arguments args) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008839 HandleScope scope;
8840 ASSERT(args.length() == 3);
8841
8842 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008843 Object* check;
8844 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
8845 if (!maybe_check->ToObject(&check)) return maybe_check;
8846 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008847 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
8848 CONVERT_NUMBER_CHECKED(int, index, Int32, args[2]);
8849
8850 // Get the frame where the debugging is performed.
8851 StackFrame::Id id = UnwrapFrameId(wrapped_id);
8852 JavaScriptFrameIterator frame_it(id);
8853 JavaScriptFrame* frame = frame_it.frame();
8854
8855 // Find the requested scope.
8856 int n = 0;
8857 ScopeIterator it(frame);
8858 for (; !it.Done() && n < index; it.Next()) {
8859 n++;
8860 }
8861 if (it.Done()) {
8862 return Heap::undefined_value();
8863 }
8864
8865 // Calculate the size of the result.
8866 int details_size = kScopeDetailsSize;
8867 Handle<FixedArray> details = Factory::NewFixedArray(details_size);
8868
8869 // Fill in scope details.
8870 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008871 Handle<JSObject> scope_object = it.ScopeObject();
8872 details->set(kScopeDetailsObjectIndex, *scope_object);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008873
8874 return *Factory::NewJSArrayWithElements(details);
8875}
8876
8877
lrn@chromium.org303ada72010-10-27 09:33:13 +00008878static MaybeObject* Runtime_DebugPrintScopes(Arguments args) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008879 HandleScope scope;
8880 ASSERT(args.length() == 0);
8881
8882#ifdef DEBUG
8883 // Print the scopes for the top frame.
8884 StackFrameLocator locator;
8885 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
8886 for (ScopeIterator it(frame); !it.Done(); it.Next()) {
8887 it.DebugPrint();
8888 }
8889#endif
8890 return Heap::undefined_value();
8891}
8892
8893
lrn@chromium.org303ada72010-10-27 09:33:13 +00008894static MaybeObject* Runtime_GetCFrames(Arguments args) {
8895 // See bug 906.
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00008896 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008897}
8898
8899
lrn@chromium.org303ada72010-10-27 09:33:13 +00008900static MaybeObject* Runtime_GetThreadCount(Arguments args) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008901 HandleScope scope;
8902 ASSERT(args.length() == 1);
8903
8904 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008905 Object* result;
8906 { MaybeObject* maybe_result = Runtime_CheckExecutionState(args);
8907 if (!maybe_result->ToObject(&result)) return maybe_result;
8908 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008909
8910 // Count all archived V8 threads.
8911 int n = 0;
8912 for (ThreadState* thread = ThreadState::FirstInUse();
8913 thread != NULL;
8914 thread = thread->Next()) {
8915 n++;
8916 }
8917
8918 // Total number of threads is current thread and archived threads.
8919 return Smi::FromInt(n + 1);
8920}
8921
8922
8923static const int kThreadDetailsCurrentThreadIndex = 0;
8924static const int kThreadDetailsThreadIdIndex = 1;
8925static const int kThreadDetailsSize = 2;
8926
8927// Return an array with thread details
8928// args[0]: number: break id
8929// args[1]: number: thread index
8930//
8931// The array returned contains the following information:
8932// 0: Is current thread?
8933// 1: Thread id
lrn@chromium.org303ada72010-10-27 09:33:13 +00008934static MaybeObject* Runtime_GetThreadDetails(Arguments args) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008935 HandleScope scope;
8936 ASSERT(args.length() == 2);
8937
8938 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008939 Object* check;
8940 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
8941 if (!maybe_check->ToObject(&check)) return maybe_check;
8942 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008943 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
8944
8945 // Allocate array for result.
8946 Handle<FixedArray> details = Factory::NewFixedArray(kThreadDetailsSize);
8947
8948 // Thread index 0 is current thread.
8949 if (index == 0) {
8950 // Fill the details.
8951 details->set(kThreadDetailsCurrentThreadIndex, Heap::true_value());
8952 details->set(kThreadDetailsThreadIdIndex,
8953 Smi::FromInt(ThreadManager::CurrentId()));
8954 } else {
8955 // Find the thread with the requested index.
8956 int n = 1;
8957 ThreadState* thread = ThreadState::FirstInUse();
8958 while (index != n && thread != NULL) {
8959 thread = thread->Next();
8960 n++;
8961 }
8962 if (thread == NULL) {
8963 return Heap::undefined_value();
8964 }
8965
8966 // Fill the details.
8967 details->set(kThreadDetailsCurrentThreadIndex, Heap::false_value());
8968 details->set(kThreadDetailsThreadIdIndex, Smi::FromInt(thread->id()));
8969 }
8970
8971 // Convert to JS array and return.
8972 return *Factory::NewJSArrayWithElements(details);
8973}
8974
8975
whesse@chromium.orge90029b2010-08-02 11:52:17 +00008976// Sets the disable break state
8977// args[0]: disable break state
lrn@chromium.org303ada72010-10-27 09:33:13 +00008978static MaybeObject* Runtime_SetDisableBreak(Arguments args) {
whesse@chromium.orge90029b2010-08-02 11:52:17 +00008979 HandleScope scope;
8980 ASSERT(args.length() == 1);
8981 CONVERT_BOOLEAN_CHECKED(disable_break, args[0]);
8982 Debug::set_disable_break(disable_break);
8983 return Heap::undefined_value();
8984}
8985
8986
lrn@chromium.org303ada72010-10-27 09:33:13 +00008987static MaybeObject* Runtime_GetBreakLocations(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008988 HandleScope scope;
8989 ASSERT(args.length() == 1);
8990
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008991 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
8992 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008993 // Find the number of break points
8994 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
8995 if (break_locations->IsUndefined()) return Heap::undefined_value();
8996 // Return array as JS array
8997 return *Factory::NewJSArrayWithElements(
8998 Handle<FixedArray>::cast(break_locations));
8999}
9000
9001
9002// Set a break point in a function
9003// args[0]: function
9004// args[1]: number: break source position (within the function source)
9005// args[2]: number: break point object
lrn@chromium.org303ada72010-10-27 09:33:13 +00009006static MaybeObject* Runtime_SetFunctionBreakPoint(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009007 HandleScope scope;
9008 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00009009 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
9010 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009011 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
9012 RUNTIME_ASSERT(source_position >= 0);
9013 Handle<Object> break_point_object_arg = args.at<Object>(2);
9014
9015 // Set break point.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00009016 Debug::SetBreakPoint(shared, break_point_object_arg, &source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009017
lrn@chromium.org32d961d2010-06-30 09:09:34 +00009018 return Smi::FromInt(source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009019}
9020
9021
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00009022Object* Runtime::FindSharedFunctionInfoInScript(Handle<Script> script,
9023 int position) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009024 // Iterate the heap looking for SharedFunctionInfo generated from the
9025 // script. The inner most SharedFunctionInfo containing the source position
9026 // for the requested break point is found.
9027 // NOTE: This might reqire several heap iterations. If the SharedFunctionInfo
9028 // which is found is not compiled it is compiled and the heap is iterated
9029 // again as the compilation might create inner functions from the newly
9030 // compiled function and the actual requested break point might be in one of
9031 // these functions.
9032 bool done = false;
9033 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +00009034 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009035 Handle<SharedFunctionInfo> target;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009036 while (!done) {
9037 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009038 for (HeapObject* obj = iterator.next();
9039 obj != NULL; obj = iterator.next()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009040 if (obj->IsSharedFunctionInfo()) {
9041 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
9042 if (shared->script() == *script) {
9043 // If the SharedFunctionInfo found has the requested script data and
9044 // contains the source position it is a candidate.
9045 int start_position = shared->function_token_position();
ager@chromium.org236ad962008-09-25 09:45:57 +00009046 if (start_position == RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009047 start_position = shared->start_position();
9048 }
9049 if (start_position <= position &&
9050 position <= shared->end_position()) {
ager@chromium.org32912102009-01-16 10:38:43 +00009051 // If there is no candidate or this function is within the current
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009052 // candidate this is the new candidate.
9053 if (target.is_null()) {
9054 target_start_position = start_position;
9055 target = shared;
9056 } else {
ager@chromium.orga1645e22009-09-09 19:27:10 +00009057 if (target_start_position == start_position &&
9058 shared->end_position() == target->end_position()) {
9059 // If a top-level function contain only one function
9060 // declartion the source for the top-level and the function is
9061 // the same. In that case prefer the non top-level function.
9062 if (!shared->is_toplevel()) {
9063 target_start_position = start_position;
9064 target = shared;
9065 }
9066 } else if (target_start_position <= start_position &&
9067 shared->end_position() <= target->end_position()) {
9068 // This containment check includes equality as a function inside
9069 // a top-level function can share either start or end position
9070 // with the top-level function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009071 target_start_position = start_position;
9072 target = shared;
9073 }
9074 }
9075 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009076 }
9077 }
9078 }
9079
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009080 if (target.is_null()) {
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00009081 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009082 }
9083
9084 // If the candidate found is compiled we are done. NOTE: when lazy
9085 // compilation of inner functions is introduced some additional checking
9086 // needs to be done here to compile inner functions.
9087 done = target->is_compiled();
9088 if (!done) {
9089 // If the candidate is not compiled compile it to reveal any inner
9090 // functions which might contain the requested source position.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009091 CompileLazyShared(target, KEEP_EXCEPTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009092 }
9093 }
9094
9095 return *target;
9096}
9097
9098
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00009099// Changes the state of a break point in a script and returns source position
9100// where break point was set. NOTE: Regarding performance see the NOTE for
9101// GetScriptFromScriptData.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009102// args[0]: script to set break point in
9103// args[1]: number: break source position (within the script source)
9104// args[2]: number: break point object
lrn@chromium.org303ada72010-10-27 09:33:13 +00009105static MaybeObject* Runtime_SetScriptBreakPoint(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009106 HandleScope scope;
9107 ASSERT(args.length() == 3);
9108 CONVERT_ARG_CHECKED(JSValue, wrapper, 0);
9109 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
9110 RUNTIME_ASSERT(source_position >= 0);
9111 Handle<Object> break_point_object_arg = args.at<Object>(2);
9112
9113 // Get the script from the script wrapper.
9114 RUNTIME_ASSERT(wrapper->value()->IsScript());
9115 Handle<Script> script(Script::cast(wrapper->value()));
9116
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00009117 Object* result = Runtime::FindSharedFunctionInfoInScript(
9118 script, source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009119 if (!result->IsUndefined()) {
9120 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
9121 // Find position within function. The script position might be before the
9122 // source position of the first function.
9123 int position;
9124 if (shared->start_position() > source_position) {
9125 position = 0;
9126 } else {
9127 position = source_position - shared->start_position();
9128 }
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00009129 Debug::SetBreakPoint(shared, break_point_object_arg, &position);
9130 position += shared->start_position();
9131 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009132 }
9133 return Heap::undefined_value();
9134}
9135
9136
9137// Clear a break point
9138// args[0]: number: break point object
lrn@chromium.org303ada72010-10-27 09:33:13 +00009139static MaybeObject* Runtime_ClearBreakPoint(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009140 HandleScope scope;
9141 ASSERT(args.length() == 1);
9142 Handle<Object> break_point_object_arg = args.at<Object>(0);
9143
9144 // Clear break point.
9145 Debug::ClearBreakPoint(break_point_object_arg);
9146
9147 return Heap::undefined_value();
9148}
9149
9150
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00009151// Change the state of break on exceptions.
9152// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
9153// args[1]: Boolean indicating on/off.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009154static MaybeObject* Runtime_ChangeBreakOnException(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009155 HandleScope scope;
9156 ASSERT(args.length() == 2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00009157 RUNTIME_ASSERT(args[0]->IsNumber());
9158 CONVERT_BOOLEAN_CHECKED(enable, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009159
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00009160 // If the number doesn't match an enum value, the ChangeBreakOnException
9161 // function will default to affecting caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009162 ExceptionBreakType type =
9163 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00009164 // Update break point state.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009165 Debug::ChangeBreakOnException(type, enable);
9166 return Heap::undefined_value();
9167}
9168
9169
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00009170// Returns the state of break on exceptions
9171// args[0]: boolean indicating uncaught exceptions
lrn@chromium.org303ada72010-10-27 09:33:13 +00009172static MaybeObject* Runtime_IsBreakOnException(Arguments args) {
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00009173 HandleScope scope;
9174 ASSERT(args.length() == 1);
9175 RUNTIME_ASSERT(args[0]->IsNumber());
9176
9177 ExceptionBreakType type =
9178 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
9179 bool result = Debug::IsBreakOnException(type);
9180 return Smi::FromInt(result);
9181}
9182
9183
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009184// Prepare for stepping
9185// args[0]: break id for checking execution state
9186// args[1]: step action from the enumeration StepAction
ager@chromium.orga1645e22009-09-09 19:27:10 +00009187// args[2]: number of times to perform the step, for step out it is the number
9188// of frames to step down.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009189static MaybeObject* Runtime_PrepareStep(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009190 HandleScope scope;
9191 ASSERT(args.length() == 3);
9192 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009193 Object* check;
9194 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
9195 if (!maybe_check->ToObject(&check)) return maybe_check;
9196 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009197 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
9198 return Top::Throw(Heap::illegal_argument_symbol());
9199 }
9200
9201 // Get the step action and check validity.
9202 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
9203 if (step_action != StepIn &&
9204 step_action != StepNext &&
9205 step_action != StepOut &&
9206 step_action != StepInMin &&
9207 step_action != StepMin) {
9208 return Top::Throw(Heap::illegal_argument_symbol());
9209 }
9210
9211 // Get the number of steps.
9212 int step_count = NumberToInt32(args[2]);
9213 if (step_count < 1) {
9214 return Top::Throw(Heap::illegal_argument_symbol());
9215 }
9216
ager@chromium.orga1645e22009-09-09 19:27:10 +00009217 // Clear all current stepping setup.
9218 Debug::ClearStepping();
9219
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009220 // Prepare step.
9221 Debug::PrepareStep(static_cast<StepAction>(step_action), step_count);
9222 return Heap::undefined_value();
9223}
9224
9225
9226// Clear all stepping set by PrepareStep.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009227static MaybeObject* Runtime_ClearStepping(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009228 HandleScope scope;
mads.s.ager31e71382008-08-13 09:32:07 +00009229 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009230 Debug::ClearStepping();
9231 return Heap::undefined_value();
9232}
9233
9234
9235// Creates a copy of the with context chain. The copy of the context chain is
9236// is linked to the function context supplied.
9237static Handle<Context> CopyWithContextChain(Handle<Context> context_chain,
9238 Handle<Context> function_context) {
9239 // At the bottom of the chain. Return the function context to link to.
9240 if (context_chain->is_function_context()) {
9241 return function_context;
9242 }
9243
9244 // Recursively copy the with contexts.
9245 Handle<Context> previous(context_chain->previous());
9246 Handle<JSObject> extension(JSObject::cast(context_chain->extension()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00009247 Handle<Context> context = CopyWithContextChain(function_context, previous);
9248 return Factory::NewWithContext(context,
9249 extension,
9250 context_chain->IsCatchContext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009251}
9252
9253
9254// Helper function to find or create the arguments object for
9255// Runtime_DebugEvaluate.
9256static Handle<Object> GetArgumentsObject(JavaScriptFrame* frame,
9257 Handle<JSFunction> function,
ager@chromium.orgb5737492010-07-15 09:29:43 +00009258 Handle<SerializedScopeInfo> scope_info,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009259 const ScopeInfo<>* sinfo,
9260 Handle<Context> function_context) {
9261 // Try to find the value of 'arguments' to pass as parameter. If it is not
9262 // found (that is the debugged function does not reference 'arguments' and
9263 // does not support eval) then create an 'arguments' object.
9264 int index;
9265 if (sinfo->number_of_stack_slots() > 0) {
ager@chromium.orgb5737492010-07-15 09:29:43 +00009266 index = scope_info->StackSlotIndex(Heap::arguments_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009267 if (index != -1) {
9268 return Handle<Object>(frame->GetExpression(index));
9269 }
9270 }
9271
9272 if (sinfo->number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
ager@chromium.orgb5737492010-07-15 09:29:43 +00009273 index = scope_info->ContextSlotIndex(Heap::arguments_symbol(), NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009274 if (index != -1) {
9275 return Handle<Object>(function_context->get(index));
9276 }
9277 }
9278
9279 const int length = frame->GetProvidedParametersCount();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009280 Handle<JSObject> arguments = Factory::NewArgumentsObject(function, length);
9281 Handle<FixedArray> array = Factory::NewFixedArray(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009282
9283 AssertNoAllocation no_gc;
9284 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009285 for (int i = 0; i < length; i++) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009286 array->set(i, frame->GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009287 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009288 arguments->set_elements(*array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009289 return arguments;
9290}
9291
9292
9293// Evaluate a piece of JavaScript in the context of a stack frame for
ager@chromium.org32912102009-01-16 10:38:43 +00009294// debugging. This is accomplished by creating a new context which in its
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009295// extension part has all the parameters and locals of the function on the
9296// stack frame. A function which calls eval with the code to evaluate is then
9297// compiled in this context and called in this context. As this context
9298// replaces the context of the function on the stack frame a new (empty)
9299// function is created as well to be used as the closure for the context.
9300// This function and the context acts as replacements for the function on the
9301// stack frame presenting the same view of the values of parameters and
9302// local variables as if the piece of JavaScript was evaluated at the point
9303// where the function on the stack frame is currently stopped.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009304static MaybeObject* Runtime_DebugEvaluate(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009305 HandleScope scope;
9306
9307 // Check the execution state and decode arguments frame and source to be
9308 // evaluated.
kasper.lundbd3ec4e2008-07-09 11:06:54 +00009309 ASSERT(args.length() == 4);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009310 Object* check_result;
9311 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(args);
9312 if (!maybe_check_result->ToObject(&check_result)) {
9313 return maybe_check_result;
9314 }
9315 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009316 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
9317 CONVERT_ARG_CHECKED(String, source, 2);
kasper.lundbd3ec4e2008-07-09 11:06:54 +00009318 CONVERT_BOOLEAN_CHECKED(disable_break, args[3]);
9319
9320 // Handle the processing of break.
9321 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009322
9323 // Get the frame where the debugging is performed.
9324 StackFrame::Id id = UnwrapFrameId(wrapped_id);
9325 JavaScriptFrameIterator it(id);
9326 JavaScriptFrame* frame = it.frame();
9327 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +00009328 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009329 ScopeInfo<> sinfo(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009330
9331 // Traverse the saved contexts chain to find the active context for the
9332 // selected frame.
9333 SaveContext* save = Top::save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009334 while (save != NULL && !save->below(frame)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009335 save = save->prev();
9336 }
9337 ASSERT(save != NULL);
9338 SaveContext savex;
9339 Top::set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009340
9341 // Create the (empty) function replacing the function on the stack frame for
9342 // the purpose of evaluating in the context created below. It is important
9343 // that this function does not describe any parameters and local variables
9344 // in the context. If it does then this will cause problems with the lookup
9345 // in Context::Lookup, where context slots for parameters and local variables
9346 // are looked at before the extension object.
9347 Handle<JSFunction> go_between =
9348 Factory::NewFunction(Factory::empty_string(), Factory::undefined_value());
9349 go_between->set_context(function->context());
9350#ifdef DEBUG
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009351 ScopeInfo<> go_between_sinfo(go_between->shared()->scope_info());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009352 ASSERT(go_between_sinfo.number_of_parameters() == 0);
9353 ASSERT(go_between_sinfo.number_of_context_slots() == 0);
9354#endif
9355
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009356 // Materialize the content of the local scope into a JSObject.
9357 Handle<JSObject> local_scope = MaterializeLocalScope(frame);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009358
9359 // Allocate a new context for the debug evaluation and set the extension
9360 // object build.
9361 Handle<Context> context =
9362 Factory::NewFunctionContext(Context::MIN_CONTEXT_SLOTS, go_between);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009363 context->set_extension(*local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009364 // Copy any with contexts present and chain them in front of this context.
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009365 Handle<Context> frame_context(Context::cast(frame->context()));
9366 Handle<Context> function_context(frame_context->fcontext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009367 context = CopyWithContextChain(frame_context, context);
9368
9369 // Wrap the evaluation statement in a new function compiled in the newly
9370 // created context. The function has one parameter which has to be called
9371 // 'arguments'. This it to have access to what would have been 'arguments' in
ager@chromium.org32912102009-01-16 10:38:43 +00009372 // the function being debugged.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009373 // function(arguments,__source__) {return eval(__source__);}
9374 static const char* source_str =
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00009375 "(function(arguments,__source__){return eval(__source__);})";
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009376 static const int source_str_length = StrLength(source_str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009377 Handle<String> function_source =
9378 Factory::NewStringFromAscii(Vector<const char>(source_str,
9379 source_str_length));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009380 Handle<SharedFunctionInfo> shared =
ager@chromium.org381abbb2009-02-25 13:23:22 +00009381 Compiler::CompileEval(function_source,
9382 context,
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009383 context->IsGlobalContext());
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009384 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009385 Handle<JSFunction> compiled_function =
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009386 Factory::NewFunctionFromSharedFunctionInfo(shared, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009387
9388 // Invoke the result of the compilation to get the evaluation function.
9389 bool has_pending_exception;
9390 Handle<Object> receiver(frame->receiver());
9391 Handle<Object> evaluation_function =
9392 Execution::Call(compiled_function, receiver, 0, NULL,
9393 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00009394 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009395
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009396 Handle<Object> arguments = GetArgumentsObject(frame, function, scope_info,
9397 &sinfo, function_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009398
9399 // Invoke the evaluation function and return the result.
9400 const int argc = 2;
9401 Object** argv[argc] = { arguments.location(),
9402 Handle<Object>::cast(source).location() };
9403 Handle<Object> result =
9404 Execution::Call(Handle<JSFunction>::cast(evaluation_function), receiver,
9405 argc, argv, &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00009406 if (has_pending_exception) return Failure::Exception();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009407
9408 // Skip the global proxy as it has no properties and always delegates to the
9409 // real global object.
9410 if (result->IsJSGlobalProxy()) {
9411 result = Handle<JSObject>(JSObject::cast(result->GetPrototype()));
9412 }
9413
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009414 return *result;
9415}
9416
9417
lrn@chromium.org303ada72010-10-27 09:33:13 +00009418static MaybeObject* Runtime_DebugEvaluateGlobal(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009419 HandleScope scope;
9420
9421 // Check the execution state and decode arguments frame and source to be
9422 // evaluated.
kasper.lundbd3ec4e2008-07-09 11:06:54 +00009423 ASSERT(args.length() == 3);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009424 Object* check_result;
9425 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(args);
9426 if (!maybe_check_result->ToObject(&check_result)) {
9427 return maybe_check_result;
9428 }
9429 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009430 CONVERT_ARG_CHECKED(String, source, 1);
kasper.lundbd3ec4e2008-07-09 11:06:54 +00009431 CONVERT_BOOLEAN_CHECKED(disable_break, args[2]);
9432
9433 // Handle the processing of break.
9434 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009435
9436 // Enter the top context from before the debugger was invoked.
9437 SaveContext save;
9438 SaveContext* top = &save;
9439 while (top != NULL && *top->context() == *Debug::debug_context()) {
9440 top = top->prev();
9441 }
9442 if (top != NULL) {
9443 Top::set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009444 }
9445
9446 // Get the global context now set to the top context from before the
9447 // debugger was invoked.
9448 Handle<Context> context = Top::global_context();
9449
9450 // Compile the source to be evaluated.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009451 Handle<SharedFunctionInfo> shared =
9452 Compiler::CompileEval(source,
9453 context,
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009454 true);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009455 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009456 Handle<JSFunction> compiled_function =
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009457 Handle<JSFunction>(Factory::NewFunctionFromSharedFunctionInfo(shared,
9458 context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009459
9460 // Invoke the result of the compilation to get the evaluation function.
9461 bool has_pending_exception;
9462 Handle<Object> receiver = Top::global();
9463 Handle<Object> result =
9464 Execution::Call(compiled_function, receiver, 0, NULL,
9465 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00009466 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009467 return *result;
9468}
9469
9470
lrn@chromium.org303ada72010-10-27 09:33:13 +00009471static MaybeObject* Runtime_DebugGetLoadedScripts(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009472 HandleScope scope;
mads.s.ager31e71382008-08-13 09:32:07 +00009473 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009474
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009475 // Fill the script objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +00009476 Handle<FixedArray> instances = Debug::GetLoadedScripts();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009477
9478 // Convert the script objects to proper JS objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +00009479 for (int i = 0; i < instances->length(); i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00009480 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
9481 // Get the script wrapper in a local handle before calling GetScriptWrapper,
9482 // because using
9483 // instances->set(i, *GetScriptWrapper(script))
9484 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
9485 // already have deferenced the instances handle.
9486 Handle<JSValue> wrapper = GetScriptWrapper(script);
9487 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009488 }
9489
9490 // Return result as a JS array.
9491 Handle<JSObject> result = Factory::NewJSObject(Top::array_function());
9492 Handle<JSArray>::cast(result)->SetContent(*instances);
9493 return *result;
9494}
9495
9496
9497// Helper function used by Runtime_DebugReferencedBy below.
9498static int DebugReferencedBy(JSObject* target,
9499 Object* instance_filter, int max_references,
9500 FixedArray* instances, int instances_size,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009501 JSFunction* arguments_function) {
9502 NoHandleAllocation ha;
9503 AssertNoAllocation no_alloc;
9504
9505 // Iterate the heap.
9506 int count = 0;
9507 JSObject* last = NULL;
9508 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009509 HeapObject* heap_obj = NULL;
9510 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009511 (max_references == 0 || count < max_references)) {
9512 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009513 if (heap_obj->IsJSObject()) {
9514 // Skip context extension objects and argument arrays as these are
9515 // checked in the context of functions using them.
9516 JSObject* obj = JSObject::cast(heap_obj);
iposva@chromium.org245aa852009-02-10 00:49:54 +00009517 if (obj->IsJSContextExtensionObject() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009518 obj->map()->constructor() == arguments_function) {
9519 continue;
9520 }
9521
9522 // Check if the JS object has a reference to the object looked for.
9523 if (obj->ReferencesObject(target)) {
9524 // Check instance filter if supplied. This is normally used to avoid
9525 // references from mirror objects (see Runtime_IsInPrototypeChain).
9526 if (!instance_filter->IsUndefined()) {
9527 Object* V = obj;
9528 while (true) {
9529 Object* prototype = V->GetPrototype();
9530 if (prototype->IsNull()) {
9531 break;
9532 }
9533 if (instance_filter == prototype) {
9534 obj = NULL; // Don't add this object.
9535 break;
9536 }
9537 V = prototype;
9538 }
9539 }
9540
9541 if (obj != NULL) {
9542 // Valid reference found add to instance array if supplied an update
9543 // count.
9544 if (instances != NULL && count < instances_size) {
9545 instances->set(count, obj);
9546 }
9547 last = obj;
9548 count++;
9549 }
9550 }
9551 }
9552 }
9553
9554 // Check for circular reference only. This can happen when the object is only
9555 // referenced from mirrors and has a circular reference in which case the
9556 // object is not really alive and would have been garbage collected if not
9557 // referenced from the mirror.
9558 if (count == 1 && last == target) {
9559 count = 0;
9560 }
9561
9562 // Return the number of referencing objects found.
9563 return count;
9564}
9565
9566
9567// Scan the heap for objects with direct references to an object
9568// args[0]: the object to find references to
9569// args[1]: constructor function for instances to exclude (Mirror)
9570// args[2]: the the maximum number of objects to return
lrn@chromium.org303ada72010-10-27 09:33:13 +00009571static MaybeObject* Runtime_DebugReferencedBy(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009572 ASSERT(args.length() == 3);
9573
9574 // First perform a full GC in order to avoid references from dead objects.
ager@chromium.orgab99eea2009-08-25 07:05:41 +00009575 Heap::CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009576
9577 // Check parameters.
9578 CONVERT_CHECKED(JSObject, target, args[0]);
9579 Object* instance_filter = args[1];
9580 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
9581 instance_filter->IsJSObject());
9582 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
9583 RUNTIME_ASSERT(max_references >= 0);
9584
9585 // Get the constructor function for context extension and arguments array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009586 JSObject* arguments_boilerplate =
9587 Top::context()->global_context()->arguments_boilerplate();
9588 JSFunction* arguments_function =
9589 JSFunction::cast(arguments_boilerplate->map()->constructor());
9590
9591 // Get the number of referencing objects.
9592 int count;
9593 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +00009594 NULL, 0, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009595
9596 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009597 Object* object;
9598 { MaybeObject* maybe_object = Heap::AllocateFixedArray(count);
9599 if (!maybe_object->ToObject(&object)) return maybe_object;
9600 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009601 FixedArray* instances = FixedArray::cast(object);
9602
9603 // Fill the referencing objects.
9604 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +00009605 instances, count, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009606
9607 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009608 Object* result;
9609 { MaybeObject* maybe_result = Heap::AllocateJSObject(
9610 Top::context()->global_context()->array_function());
9611 if (!maybe_result->ToObject(&result)) return maybe_result;
9612 }
9613 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009614 return result;
9615}
9616
9617
9618// Helper function used by Runtime_DebugConstructedBy below.
9619static int DebugConstructedBy(JSFunction* constructor, int max_references,
9620 FixedArray* instances, int instances_size) {
9621 AssertNoAllocation no_alloc;
9622
9623 // Iterate the heap.
9624 int count = 0;
9625 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009626 HeapObject* heap_obj = NULL;
9627 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009628 (max_references == 0 || count < max_references)) {
9629 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009630 if (heap_obj->IsJSObject()) {
9631 JSObject* obj = JSObject::cast(heap_obj);
9632 if (obj->map()->constructor() == constructor) {
9633 // Valid reference found add to instance array if supplied an update
9634 // count.
9635 if (instances != NULL && count < instances_size) {
9636 instances->set(count, obj);
9637 }
9638 count++;
9639 }
9640 }
9641 }
9642
9643 // Return the number of referencing objects found.
9644 return count;
9645}
9646
9647
9648// Scan the heap for objects constructed by a specific function.
9649// args[0]: the constructor to find instances of
9650// args[1]: the the maximum number of objects to return
lrn@chromium.org303ada72010-10-27 09:33:13 +00009651static MaybeObject* Runtime_DebugConstructedBy(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009652 ASSERT(args.length() == 2);
9653
9654 // First perform a full GC in order to avoid dead objects.
ager@chromium.orgab99eea2009-08-25 07:05:41 +00009655 Heap::CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009656
9657 // Check parameters.
9658 CONVERT_CHECKED(JSFunction, constructor, args[0]);
9659 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
9660 RUNTIME_ASSERT(max_references >= 0);
9661
9662 // Get the number of referencing objects.
9663 int count;
9664 count = DebugConstructedBy(constructor, max_references, NULL, 0);
9665
9666 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009667 Object* object;
9668 { MaybeObject* maybe_object = Heap::AllocateFixedArray(count);
9669 if (!maybe_object->ToObject(&object)) return maybe_object;
9670 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009671 FixedArray* instances = FixedArray::cast(object);
9672
9673 // Fill the referencing objects.
9674 count = DebugConstructedBy(constructor, max_references, instances, count);
9675
9676 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009677 Object* result;
9678 { MaybeObject* maybe_result = Heap::AllocateJSObject(
9679 Top::context()->global_context()->array_function());
9680 if (!maybe_result->ToObject(&result)) return maybe_result;
9681 }
9682 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009683 return result;
9684}
9685
9686
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009687// Find the effective prototype object as returned by __proto__.
9688// args[0]: the object to find the prototype for.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009689static MaybeObject* Runtime_DebugGetPrototype(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009690 ASSERT(args.length() == 1);
9691
9692 CONVERT_CHECKED(JSObject, obj, args[0]);
9693
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009694 // Use the __proto__ accessor.
9695 return Accessors::ObjectPrototype.getter(obj, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009696}
9697
9698
lrn@chromium.org303ada72010-10-27 09:33:13 +00009699static MaybeObject* Runtime_SystemBreak(Arguments args) {
mads.s.ager31e71382008-08-13 09:32:07 +00009700 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009701 CPU::DebugBreak();
9702 return Heap::undefined_value();
9703}
9704
9705
lrn@chromium.org303ada72010-10-27 09:33:13 +00009706static MaybeObject* Runtime_DebugDisassembleFunction(Arguments args) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009707#ifdef DEBUG
9708 HandleScope scope;
9709 ASSERT(args.length() == 1);
9710 // Get the function and make sure it is compiled.
9711 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009712 Handle<SharedFunctionInfo> shared(func->shared());
9713 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009714 return Failure::Exception();
9715 }
9716 func->code()->PrintLn();
9717#endif // DEBUG
9718 return Heap::undefined_value();
9719}
ager@chromium.org9085a012009-05-11 19:22:57 +00009720
9721
lrn@chromium.org303ada72010-10-27 09:33:13 +00009722static MaybeObject* Runtime_DebugDisassembleConstructor(Arguments args) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00009723#ifdef DEBUG
9724 HandleScope scope;
9725 ASSERT(args.length() == 1);
9726 // Get the function and make sure it is compiled.
9727 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009728 Handle<SharedFunctionInfo> shared(func->shared());
9729 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00009730 return Failure::Exception();
9731 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009732 shared->construct_stub()->PrintLn();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00009733#endif // DEBUG
9734 return Heap::undefined_value();
9735}
9736
9737
lrn@chromium.org303ada72010-10-27 09:33:13 +00009738static MaybeObject* Runtime_FunctionGetInferredName(Arguments args) {
ager@chromium.org9085a012009-05-11 19:22:57 +00009739 NoHandleAllocation ha;
9740 ASSERT(args.length() == 1);
9741
9742 CONVERT_CHECKED(JSFunction, f, args[0]);
9743 return f->shared()->inferred_name();
9744}
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009745
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009746
9747static int FindSharedFunctionInfosForScript(Script* script,
9748 FixedArray* buffer) {
9749 AssertNoAllocation no_allocations;
9750
9751 int counter = 0;
9752 int buffer_size = buffer->length();
9753 HeapIterator iterator;
9754 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
9755 ASSERT(obj != NULL);
9756 if (!obj->IsSharedFunctionInfo()) {
9757 continue;
9758 }
9759 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
9760 if (shared->script() != script) {
9761 continue;
9762 }
9763 if (counter < buffer_size) {
9764 buffer->set(counter, shared);
9765 }
9766 counter++;
9767 }
9768 return counter;
9769}
9770
9771// For a script finds all SharedFunctionInfo's in the heap that points
9772// to this script. Returns JSArray of SharedFunctionInfo wrapped
9773// in OpaqueReferences.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009774static MaybeObject* Runtime_LiveEditFindSharedFunctionInfosForScript(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009775 Arguments args) {
9776 ASSERT(args.length() == 1);
9777 HandleScope scope;
9778 CONVERT_CHECKED(JSValue, script_value, args[0]);
9779
9780 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
9781
9782 const int kBufferSize = 32;
9783
9784 Handle<FixedArray> array;
9785 array = Factory::NewFixedArray(kBufferSize);
9786 int number = FindSharedFunctionInfosForScript(*script, *array);
9787 if (number > kBufferSize) {
9788 array = Factory::NewFixedArray(number);
9789 FindSharedFunctionInfosForScript(*script, *array);
9790 }
9791
9792 Handle<JSArray> result = Factory::NewJSArrayWithElements(array);
9793 result->set_length(Smi::FromInt(number));
9794
9795 LiveEdit::WrapSharedFunctionInfos(result);
9796
9797 return *result;
9798}
9799
9800// For a script calculates compilation information about all its functions.
9801// The script source is explicitly specified by the second argument.
9802// The source of the actual script is not used, however it is important that
9803// all generated code keeps references to this particular instance of script.
9804// Returns a JSArray of compilation infos. The array is ordered so that
9805// each function with all its descendant is always stored in a continues range
9806// with the function itself going first. The root function is a script function.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009807static MaybeObject* Runtime_LiveEditGatherCompileInfo(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009808 ASSERT(args.length() == 2);
9809 HandleScope scope;
9810 CONVERT_CHECKED(JSValue, script, args[0]);
9811 CONVERT_ARG_CHECKED(String, source, 1);
9812 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
9813
9814 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
9815
9816 if (Top::has_pending_exception()) {
9817 return Failure::Exception();
9818 }
9819
9820 return result;
9821}
9822
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009823// Changes the source of the script to a new_source.
9824// If old_script_name is provided (i.e. is a String), also creates a copy of
9825// the script with its original source and sends notification to debugger.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009826static MaybeObject* Runtime_LiveEditReplaceScript(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009827 ASSERT(args.length() == 3);
9828 HandleScope scope;
9829 CONVERT_CHECKED(JSValue, original_script_value, args[0]);
9830 CONVERT_ARG_CHECKED(String, new_source, 1);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009831 Handle<Object> old_script_name(args[2]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009832
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009833 CONVERT_CHECKED(Script, original_script_pointer,
9834 original_script_value->value());
9835 Handle<Script> original_script(original_script_pointer);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009836
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009837 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
9838 new_source,
9839 old_script_name);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009840
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009841 if (old_script->IsScript()) {
9842 Handle<Script> script_handle(Script::cast(old_script));
9843 return *(GetScriptWrapper(script_handle));
9844 } else {
9845 return Heap::null_value();
9846 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009847}
9848
9849// Replaces code of SharedFunctionInfo with a new one.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009850static MaybeObject* Runtime_LiveEditReplaceFunctionCode(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009851 ASSERT(args.length() == 2);
9852 HandleScope scope;
9853 CONVERT_ARG_CHECKED(JSArray, new_compile_info, 0);
9854 CONVERT_ARG_CHECKED(JSArray, shared_info, 1);
9855
ager@chromium.orgac091b72010-05-05 07:34:42 +00009856 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009857}
9858
9859// Connects SharedFunctionInfo to another script.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009860static MaybeObject* Runtime_LiveEditFunctionSetScript(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009861 ASSERT(args.length() == 2);
9862 HandleScope scope;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009863 Handle<Object> function_object(args[0]);
9864 Handle<Object> script_object(args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009865
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009866 if (function_object->IsJSValue()) {
9867 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
9868 if (script_object->IsJSValue()) {
9869 CONVERT_CHECKED(Script, script, JSValue::cast(*script_object)->value());
9870 script_object = Handle<Object>(script);
9871 }
9872
9873 LiveEdit::SetFunctionScript(function_wrapper, script_object);
9874 } else {
9875 // Just ignore this. We may not have a SharedFunctionInfo for some functions
9876 // and we check it in this function.
9877 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009878
9879 return Heap::undefined_value();
9880}
9881
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009882
9883// In a code of a parent function replaces original function as embedded object
9884// with a substitution one.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009885static MaybeObject* Runtime_LiveEditReplaceRefToNestedFunction(Arguments args) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009886 ASSERT(args.length() == 3);
9887 HandleScope scope;
9888
9889 CONVERT_ARG_CHECKED(JSValue, parent_wrapper, 0);
9890 CONVERT_ARG_CHECKED(JSValue, orig_wrapper, 1);
9891 CONVERT_ARG_CHECKED(JSValue, subst_wrapper, 2);
9892
9893 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
9894 subst_wrapper);
9895
9896 return Heap::undefined_value();
9897}
9898
9899
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009900// Updates positions of a shared function info (first parameter) according
9901// to script source change. Text change is described in second parameter as
9902// array of groups of 3 numbers:
9903// (change_begin, change_end, change_end_new_position).
9904// Each group describes a change in text; groups are sorted by change_begin.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009905static MaybeObject* Runtime_LiveEditPatchFunctionPositions(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009906 ASSERT(args.length() == 2);
9907 HandleScope scope;
9908 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
9909 CONVERT_ARG_CHECKED(JSArray, position_change_array, 1);
9910
ager@chromium.orgac091b72010-05-05 07:34:42 +00009911 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009912}
9913
9914
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009915// For array of SharedFunctionInfo's (each wrapped in JSValue)
9916// checks that none of them have activations on stacks (of any thread).
9917// Returns array of the same length with corresponding results of
9918// LiveEdit::FunctionPatchabilityStatus type.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009919static MaybeObject* Runtime_LiveEditCheckAndDropActivations(Arguments args) {
ager@chromium.org357bf652010-04-12 11:30:10 +00009920 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009921 HandleScope scope;
9922 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
ager@chromium.org357bf652010-04-12 11:30:10 +00009923 CONVERT_BOOLEAN_CHECKED(do_drop, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009924
ager@chromium.org357bf652010-04-12 11:30:10 +00009925 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009926}
9927
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00009928// Compares 2 strings line-by-line and returns diff in form of JSArray of
fschneider@chromium.org013f3e12010-04-26 13:27:52 +00009929// triplets (pos1, pos1_end, pos2_end) describing list of diff chunks.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009930static MaybeObject* Runtime_LiveEditCompareStringsLinewise(Arguments args) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00009931 ASSERT(args.length() == 2);
9932 HandleScope scope;
9933 CONVERT_ARG_CHECKED(String, s1, 0);
9934 CONVERT_ARG_CHECKED(String, s2, 1);
9935
9936 return *LiveEdit::CompareStringsLinewise(s1, s2);
9937}
9938
9939
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009940
fschneider@chromium.org086aac62010-03-17 13:18:24 +00009941// A testing entry. Returns statement position which is the closest to
9942// source_position.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009943static MaybeObject* Runtime_GetFunctionCodePositionFromSource(Arguments args) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00009944 ASSERT(args.length() == 2);
9945 HandleScope scope;
9946 CONVERT_ARG_CHECKED(JSFunction, function, 0);
9947 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
9948
9949 Handle<Code> code(function->code());
9950
9951 RelocIterator it(*code, 1 << RelocInfo::STATEMENT_POSITION);
9952 int closest_pc = 0;
9953 int distance = kMaxInt;
9954 while (!it.done()) {
9955 int statement_position = static_cast<int>(it.rinfo()->data());
9956 // Check if this break point is closer that what was previously found.
9957 if (source_position <= statement_position &&
9958 statement_position - source_position < distance) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00009959 closest_pc =
9960 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
fschneider@chromium.org086aac62010-03-17 13:18:24 +00009961 distance = statement_position - source_position;
9962 // Check whether we can't get any closer.
9963 if (distance == 0) break;
9964 }
9965 it.next();
9966 }
9967
9968 return Smi::FromInt(closest_pc);
9969}
9970
9971
ager@chromium.org357bf652010-04-12 11:30:10 +00009972// Calls specified function with or without entering the debugger.
9973// This is used in unit tests to run code as if debugger is entered or simply
9974// to have a stack with C++ frame in the middle.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009975static MaybeObject* Runtime_ExecuteInDebugContext(Arguments args) {
ager@chromium.org357bf652010-04-12 11:30:10 +00009976 ASSERT(args.length() == 2);
9977 HandleScope scope;
9978 CONVERT_ARG_CHECKED(JSFunction, function, 0);
9979 CONVERT_BOOLEAN_CHECKED(without_debugger, args[1]);
9980
9981 Handle<Object> result;
9982 bool pending_exception;
9983 {
9984 if (without_debugger) {
9985 result = Execution::Call(function, Top::global(), 0, NULL,
9986 &pending_exception);
9987 } else {
9988 EnterDebugger enter_debugger;
9989 result = Execution::Call(function, Top::global(), 0, NULL,
9990 &pending_exception);
9991 }
9992 }
9993 if (!pending_exception) {
9994 return *result;
9995 } else {
9996 return Failure::Exception();
9997 }
9998}
9999
10000
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010001#endif // ENABLE_DEBUGGER_SUPPORT
10002
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010003#ifdef ENABLE_LOGGING_AND_PROFILING
10004
lrn@chromium.org303ada72010-10-27 09:33:13 +000010005static MaybeObject* Runtime_ProfilerResume(Arguments args) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010006 NoHandleAllocation ha;
ager@chromium.org5c838252010-02-19 08:53:10 +000010007 ASSERT(args.length() == 2);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010008
10009 CONVERT_CHECKED(Smi, smi_modules, args[0]);
ager@chromium.org5c838252010-02-19 08:53:10 +000010010 CONVERT_CHECKED(Smi, smi_tag, args[1]);
10011 v8::V8::ResumeProfilerEx(smi_modules->value(), smi_tag->value());
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010012 return Heap::undefined_value();
10013}
10014
10015
lrn@chromium.org303ada72010-10-27 09:33:13 +000010016static MaybeObject* Runtime_ProfilerPause(Arguments args) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010017 NoHandleAllocation ha;
ager@chromium.org5c838252010-02-19 08:53:10 +000010018 ASSERT(args.length() == 2);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010019
10020 CONVERT_CHECKED(Smi, smi_modules, args[0]);
ager@chromium.org5c838252010-02-19 08:53:10 +000010021 CONVERT_CHECKED(Smi, smi_tag, args[1]);
10022 v8::V8::PauseProfilerEx(smi_modules->value(), smi_tag->value());
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010023 return Heap::undefined_value();
10024}
10025
10026#endif // ENABLE_LOGGING_AND_PROFILING
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010027
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010028// Finds the script object from the script data. NOTE: This operation uses
10029// heap traversal to find the function generated for the source position
10030// for the requested break point. For lazily compiled functions several heap
10031// traversals might be required rendering this operation as a rather slow
10032// operation. However for setting break points which is normally done through
10033// some kind of user interaction the performance is not crucial.
10034static Handle<Object> Runtime_GetScriptFromScriptName(
10035 Handle<String> script_name) {
10036 // Scan the heap for Script objects to find the script with the requested
10037 // script data.
10038 Handle<Script> script;
10039 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010040 HeapObject* obj = NULL;
10041 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010042 // If a script is found check if it has the script data requested.
10043 if (obj->IsScript()) {
10044 if (Script::cast(obj)->name()->IsString()) {
10045 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
10046 script = Handle<Script>(Script::cast(obj));
10047 }
10048 }
10049 }
10050 }
10051
10052 // If no script with the requested script data is found return undefined.
10053 if (script.is_null()) return Factory::undefined_value();
10054
10055 // Return the script found.
10056 return GetScriptWrapper(script);
10057}
10058
10059
10060// Get the script object from script data. NOTE: Regarding performance
10061// see the NOTE for GetScriptFromScriptData.
10062// args[0]: script data for the script to find the source for
lrn@chromium.org303ada72010-10-27 09:33:13 +000010063static MaybeObject* Runtime_GetScript(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010064 HandleScope scope;
10065
10066 ASSERT(args.length() == 1);
10067
10068 CONVERT_CHECKED(String, script_name, args[0]);
10069
10070 // Find the requested script.
10071 Handle<Object> result =
10072 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
10073 return *result;
10074}
10075
10076
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010077// Determines whether the given stack frame should be displayed in
10078// a stack trace. The caller is the error constructor that asked
10079// for the stack trace to be collected. The first time a construct
10080// call to this function is encountered it is skipped. The seen_caller
10081// in/out parameter is used to remember if the caller has been seen
10082// yet.
10083static bool ShowFrameInStackTrace(StackFrame* raw_frame, Object* caller,
10084 bool* seen_caller) {
10085 // Only display JS frames.
10086 if (!raw_frame->is_java_script())
10087 return false;
10088 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
10089 Object* raw_fun = frame->function();
10090 // Not sure when this can happen but skip it just in case.
10091 if (!raw_fun->IsJSFunction())
10092 return false;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010093 if ((raw_fun == caller) && !(*seen_caller)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010094 *seen_caller = true;
10095 return false;
10096 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010097 // Skip all frames until we've seen the caller. Also, skip the most
10098 // obvious builtin calls. Some builtin calls (such as Number.ADD
10099 // which is invoked using 'call') are very difficult to recognize
10100 // so we're leaving them in for now.
10101 return *seen_caller && !frame->receiver()->IsJSBuiltinsObject();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010102}
10103
10104
10105// Collect the raw data for a stack trace. Returns an array of three
10106// element segments each containing a receiver, function and native
10107// code offset.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010108static MaybeObject* Runtime_CollectStackTrace(Arguments args) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010109 ASSERT_EQ(args.length(), 2);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010110 Handle<Object> caller = args.at<Object>(0);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010111 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[1]);
10112
10113 HandleScope scope;
10114
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000010115 limit = Max(limit, 0); // Ensure that limit is not negative.
10116 int initial_size = Min(limit, 10);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010117 Handle<JSArray> result = Factory::NewJSArray(initial_size * 3);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010118
10119 StackFrameIterator iter;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010120 // If the caller parameter is a function we skip frames until we're
10121 // under it before starting to collect.
10122 bool seen_caller = !caller->IsJSFunction();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010123 int cursor = 0;
10124 int frames_seen = 0;
10125 while (!iter.done() && frames_seen < limit) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010126 StackFrame* raw_frame = iter.frame();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010127 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010128 frames_seen++;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010129 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010130 Object* recv = frame->receiver();
10131 Object* fun = frame->function();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010132 Address pc = frame->pc();
10133 Address start = frame->code()->address();
ager@chromium.orgc4c92722009-11-18 14:12:51 +000010134 Smi* offset = Smi::FromInt(static_cast<int>(pc - start));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010135 FixedArray* elements = FixedArray::cast(result->elements());
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010136 if (cursor + 2 < elements->length()) {
10137 elements->set(cursor++, recv);
10138 elements->set(cursor++, fun);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010139 elements->set(cursor++, offset);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010140 } else {
10141 HandleScope scope;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010142 Handle<Object> recv_handle(recv);
10143 Handle<Object> fun_handle(fun);
10144 SetElement(result, cursor++, recv_handle);
10145 SetElement(result, cursor++, fun_handle);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010146 SetElement(result, cursor++, Handle<Smi>(offset));
10147 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010148 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010149 iter.Advance();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010150 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010151
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010152 result->set_length(Smi::FromInt(cursor));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010153 return *result;
10154}
10155
10156
ager@chromium.org3811b432009-10-28 14:53:37 +000010157// Returns V8 version as a string.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010158static MaybeObject* Runtime_GetV8Version(Arguments args) {
ager@chromium.org3811b432009-10-28 14:53:37 +000010159 ASSERT_EQ(args.length(), 0);
10160
10161 NoHandleAllocation ha;
10162
10163 const char* version_string = v8::V8::GetVersion();
10164
10165 return Heap::AllocateStringFromAscii(CStrVector(version_string), NOT_TENURED);
10166}
10167
10168
lrn@chromium.org303ada72010-10-27 09:33:13 +000010169static MaybeObject* Runtime_Abort(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010170 ASSERT(args.length() == 2);
10171 OS::PrintError("abort: %s\n", reinterpret_cast<char*>(args[0]) +
10172 Smi::cast(args[1])->value());
10173 Top::PrintStack();
10174 OS::Abort();
10175 UNREACHABLE();
10176 return NULL;
10177}
10178
10179
lrn@chromium.org303ada72010-10-27 09:33:13 +000010180MUST_USE_RESULT static MaybeObject* CacheMiss(FixedArray* cache_obj,
10181 int index,
10182 Object* key_obj) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010183 ASSERT(index % 2 == 0); // index of the key
10184 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
10185 ASSERT(index < cache_obj->length());
10186
10187 HandleScope scope;
10188
10189 Handle<FixedArray> cache(cache_obj);
10190 Handle<Object> key(key_obj);
10191 Handle<JSFunction> factory(JSFunction::cast(
10192 cache->get(JSFunctionResultCache::kFactoryIndex)));
10193 // TODO(antonm): consider passing a receiver when constructing a cache.
10194 Handle<Object> receiver(Top::global_context()->global());
10195
10196 Handle<Object> value;
10197 {
10198 // This handle is nor shared, nor used later, so it's safe.
10199 Object** argv[] = { key.location() };
10200 bool pending_exception = false;
10201 value = Execution::Call(factory,
10202 receiver,
10203 1,
10204 argv,
10205 &pending_exception);
10206 if (pending_exception) return Failure::Exception();
10207 }
10208
10209 cache->set(index, *key);
10210 cache->set(index + 1, *value);
10211 cache->set(JSFunctionResultCache::kFingerIndex, Smi::FromInt(index));
10212
10213 return *value;
10214}
10215
10216
lrn@chromium.org303ada72010-10-27 09:33:13 +000010217static MaybeObject* Runtime_GetFromCache(Arguments args) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010218 // This is only called from codegen, so checks might be more lax.
10219 CONVERT_CHECKED(FixedArray, cache, args[0]);
10220 Object* key = args[1];
10221
10222 const int finger_index =
10223 Smi::cast(cache->get(JSFunctionResultCache::kFingerIndex))->value();
10224
10225 Object* o = cache->get(finger_index);
10226 if (o == key) {
10227 // The fastest case: hit the same place again.
10228 return cache->get(finger_index + 1);
10229 }
10230
10231 for (int i = finger_index - 2;
10232 i >= JSFunctionResultCache::kEntriesIndex;
10233 i -= 2) {
10234 o = cache->get(i);
10235 if (o == key) {
10236 cache->set(JSFunctionResultCache::kFingerIndex, Smi::FromInt(i));
10237 return cache->get(i + 1);
10238 }
10239 }
10240
10241 const int size =
10242 Smi::cast(cache->get(JSFunctionResultCache::kCacheSizeIndex))->value();
10243 ASSERT(size <= cache->length());
10244
10245 for (int i = size - 2; i > finger_index; i -= 2) {
10246 o = cache->get(i);
10247 if (o == key) {
10248 cache->set(JSFunctionResultCache::kFingerIndex, Smi::FromInt(i));
10249 return cache->get(i + 1);
10250 }
10251 }
10252
10253 // Cache miss. If we have spare room, put new data into it, otherwise
10254 // evict post finger entry which must be least recently used.
10255 if (size < cache->length()) {
10256 cache->set(JSFunctionResultCache::kCacheSizeIndex, Smi::FromInt(size + 2));
10257 return CacheMiss(cache, size, key);
10258 } else {
antonm@chromium.org397e23c2010-04-21 12:00:05 +000010259 int target_index = finger_index + JSFunctionResultCache::kEntrySize;
10260 if (target_index == cache->length()) {
10261 target_index = JSFunctionResultCache::kEntriesIndex;
10262 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010263 return CacheMiss(cache, target_index, key);
10264 }
10265}
10266
kasper.lund44510672008-07-25 07:37:58 +000010267#ifdef DEBUG
10268// ListNatives is ONLY used by the fuzz-natives.js in debug mode
10269// Exclude the code in release mode.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010270static MaybeObject* Runtime_ListNatives(Arguments args) {
mads.s.ager31e71382008-08-13 09:32:07 +000010271 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010272 HandleScope scope;
10273 Handle<JSArray> result = Factory::NewJSArray(0);
10274 int index = 0;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000010275 bool inline_runtime_functions = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +000010276#define ADD_ENTRY(Name, argc, ressize) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010277 { \
10278 HandleScope inner; \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000010279 Handle<String> name; \
10280 /* Inline runtime functions have an underscore in front of the name. */ \
10281 if (inline_runtime_functions) { \
10282 name = Factory::NewStringFromAscii( \
10283 Vector<const char>("_" #Name, StrLength("_" #Name))); \
10284 } else { \
10285 name = Factory::NewStringFromAscii( \
10286 Vector<const char>(#Name, StrLength(#Name))); \
10287 } \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010288 Handle<JSArray> pair = Factory::NewJSArray(0); \
10289 SetElement(pair, 0, name); \
10290 SetElement(pair, 1, Handle<Smi>(Smi::FromInt(argc))); \
10291 SetElement(result, index++, pair); \
10292 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000010293 inline_runtime_functions = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010294 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000010295 inline_runtime_functions = true;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010296 INLINE_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000010297 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010298#undef ADD_ENTRY
10299 return *result;
10300}
kasper.lund44510672008-07-25 07:37:58 +000010301#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010302
10303
lrn@chromium.org303ada72010-10-27 09:33:13 +000010304static MaybeObject* Runtime_Log(Arguments args) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000010305 ASSERT(args.length() == 2);
ager@chromium.org381abbb2009-02-25 13:23:22 +000010306 CONVERT_CHECKED(String, format, args[0]);
10307 CONVERT_CHECKED(JSArray, elms, args[1]);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000010308 Vector<const char> chars = format->ToAsciiVector();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000010309 Logger::LogRuntime(chars, elms);
10310 return Heap::undefined_value();
10311}
10312
10313
lrn@chromium.org303ada72010-10-27 09:33:13 +000010314static MaybeObject* Runtime_IS_VAR(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010315 UNREACHABLE(); // implemented as macro in the parser
10316 return NULL;
10317}
10318
10319
10320// ----------------------------------------------------------------------------
10321// Implementation of Runtime
10322
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010323#define F(name, number_of_args, result_size) \
10324 { Runtime::k##name, Runtime::RUNTIME, #name, \
10325 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010326
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010327
10328#define I(name, number_of_args, result_size) \
10329 { Runtime::kInline##name, Runtime::INLINE, \
10330 "_" #name, NULL, number_of_args, result_size },
10331
10332Runtime::Function kIntrinsicFunctions[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010333 RUNTIME_FUNCTION_LIST(F)
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010334 INLINE_FUNCTION_LIST(I)
10335 INLINE_RUNTIME_FUNCTION_LIST(I)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010336};
10337
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010338
lrn@chromium.org303ada72010-10-27 09:33:13 +000010339MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Object* dictionary) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010340 ASSERT(dictionary != NULL);
10341 ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
10342 for (int i = 0; i < kNumFunctions; ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000010343 Object* name_symbol;
10344 { MaybeObject* maybe_name_symbol =
10345 Heap::LookupAsciiSymbol(kIntrinsicFunctions[i].name);
10346 if (!maybe_name_symbol->ToObject(&name_symbol)) return maybe_name_symbol;
10347 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010348 StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010349 { MaybeObject* maybe_dictionary = string_dictionary->Add(
10350 String::cast(name_symbol),
10351 Smi::FromInt(i),
10352 PropertyDetails(NONE, NORMAL));
10353 if (!maybe_dictionary->ToObject(&dictionary)) {
10354 // Non-recoverable failure. Calling code must restart heap
10355 // initialization.
10356 return maybe_dictionary;
10357 }
10358 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010359 }
10360 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010361}
10362
10363
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010364Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
10365 int entry = Heap::intrinsic_function_names()->FindEntry(*name);
10366 if (entry != kNotFound) {
10367 Object* smi_index = Heap::intrinsic_function_names()->ValueAt(entry);
10368 int function_index = Smi::cast(smi_index)->value();
10369 return &(kIntrinsicFunctions[function_index]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010370 }
10371 return NULL;
10372}
10373
10374
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010375Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
10376 return &(kIntrinsicFunctions[static_cast<int>(id)]);
10377}
10378
10379
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010380void Runtime::PerformGC(Object* result) {
10381 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010382 if (failure->IsRetryAfterGC()) {
10383 // Try to do a garbage collection; ignore it if it fails. The C
10384 // entry stub will throw an out-of-memory exception in that case.
whesse@chromium.org4a5224e2010-10-20 12:37:07 +000010385 Heap::CollectGarbage(failure->allocation_space());
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010386 } else {
10387 // Handle last resort GC and make sure to allow future allocations
10388 // to grow the heap without causing GCs (if possible).
10389 Counters::gc_last_resort_from_js.Increment();
ager@chromium.orgab99eea2009-08-25 07:05:41 +000010390 Heap::CollectAllGarbage(false);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010391 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010392}
10393
10394
10395} } // namespace v8::internal