blob: 0fd2f8b4bfc51f4e0dd6eb9675b227ad75f84a91 [file] [log] [blame]
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001// Copyright 2010 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include <stdlib.h>
29
30#include "v8.h"
31
32#include "accessors.h"
33#include "api.h"
34#include "arguments.h"
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000035#include "codegen.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000036#include "compilation-cache.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000037#include "compiler.h"
38#include "cpu.h"
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000039#include "dateparser-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000040#include "debug.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000041#include "deoptimizer.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000042#include "execution.h"
43#include "jsregexp.h"
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000044#include "liveedit.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000045#include "parser.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000046#include "platform.h"
47#include "runtime.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000048#include "runtime-profiler.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000049#include "scopeinfo.h"
ager@chromium.org7c537e22008-10-16 08:43:32 +000050#include "smart-pointer.h"
ager@chromium.org18ad94b2009-09-02 08:22:29 +000051#include "stub-cache.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000052#include "v8threads.h"
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000053#include "string-search.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000054
kasperl@chromium.org71affb52009-05-26 05:44:31 +000055namespace v8 {
56namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000057
58
ager@chromium.org3e875802009-06-29 08:26:34 +000059#define RUNTIME_ASSERT(value) \
60 if (!(value)) return Top::ThrowIllegalOperation();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000061
62// Cast the given object to a value of the specified type and store
63// it in a variable with the given name. If the object is not of the
64// expected type call IllegalOperation and return.
65#define CONVERT_CHECKED(Type, name, obj) \
66 RUNTIME_ASSERT(obj->Is##Type()); \
67 Type* name = Type::cast(obj);
68
69#define CONVERT_ARG_CHECKED(Type, name, index) \
70 RUNTIME_ASSERT(args[index]->Is##Type()); \
71 Handle<Type> name = args.at<Type>(index);
72
kasper.lundbd3ec4e2008-07-09 11:06:54 +000073// Cast the given object to a boolean and store it in a variable with
74// the given name. If the object is not a boolean call IllegalOperation
75// and return.
76#define CONVERT_BOOLEAN_CHECKED(name, obj) \
77 RUNTIME_ASSERT(obj->IsBoolean()); \
78 bool name = (obj)->IsTrue();
79
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000080// Cast the given object to a Smi and store its value in an int variable
81// with the given name. If the object is not a Smi call IllegalOperation
82// and return.
83#define CONVERT_SMI_CHECKED(name, obj) \
84 RUNTIME_ASSERT(obj->IsSmi()); \
85 int name = Smi::cast(obj)->value();
86
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000087// Cast the given object to a double and store it in a variable with
88// the given name. If the object is not a number (as opposed to
89// the number not-a-number) call IllegalOperation and return.
90#define CONVERT_DOUBLE_CHECKED(name, obj) \
91 RUNTIME_ASSERT(obj->IsNumber()); \
92 double name = (obj)->Number();
93
94// Call the specified converter on the object *comand store the result in
95// a variable of the specified type with the given name. If the
96// object is not a Number call IllegalOperation and return.
97#define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \
98 RUNTIME_ASSERT(obj->IsNumber()); \
99 type name = NumberTo##Type(obj);
100
101// Non-reentrant string buffer for efficient general use in this file.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000102static StaticResource<StringInputBuffer> runtime_string_input_buffer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000103
104
lrn@chromium.org303ada72010-10-27 09:33:13 +0000105MUST_USE_RESULT static MaybeObject* DeepCopyBoilerplate(JSObject* boilerplate) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000106 StackLimitCheck check;
107 if (check.HasOverflowed()) return Top::StackOverflow();
108
lrn@chromium.org303ada72010-10-27 09:33:13 +0000109 Object* result;
110 { MaybeObject* maybe_result = Heap::CopyJSObject(boilerplate);
111 if (!maybe_result->ToObject(&result)) return maybe_result;
112 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000113 JSObject* copy = JSObject::cast(result);
114
115 // Deep copy local properties.
116 if (copy->HasFastProperties()) {
117 FixedArray* properties = copy->properties();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000118 for (int i = 0; i < properties->length(); i++) {
119 Object* value = properties->get(i);
120 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000121 JSObject* js_object = JSObject::cast(value);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000122 { MaybeObject* maybe_result = DeepCopyBoilerplate(js_object);
123 if (!maybe_result->ToObject(&result)) return maybe_result;
124 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000125 properties->set(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000126 }
127 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000128 int nof = copy->map()->inobject_properties();
129 for (int i = 0; i < nof; i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000130 Object* value = copy->InObjectPropertyAt(i);
131 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000132 JSObject* js_object = JSObject::cast(value);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000133 { MaybeObject* maybe_result = DeepCopyBoilerplate(js_object);
134 if (!maybe_result->ToObject(&result)) return maybe_result;
135 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000136 copy->InObjectPropertyAtPut(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000137 }
138 }
139 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000140 { MaybeObject* maybe_result =
141 Heap::AllocateFixedArray(copy->NumberOfLocalProperties(NONE));
142 if (!maybe_result->ToObject(&result)) return maybe_result;
143 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000144 FixedArray* names = FixedArray::cast(result);
145 copy->GetLocalPropertyNames(names, 0);
146 for (int i = 0; i < names->length(); i++) {
147 ASSERT(names->get(i)->IsString());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000148 String* key_string = String::cast(names->get(i));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000149 PropertyAttributes attributes =
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000150 copy->GetLocalPropertyAttribute(key_string);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000151 // Only deep copy fields from the object literal expression.
152 // In particular, don't try to copy the length attribute of
153 // an array.
154 if (attributes != NONE) continue;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000155 Object* value =
156 copy->GetProperty(key_string, &attributes)->ToObjectUnchecked();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000157 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000158 JSObject* js_object = JSObject::cast(value);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000159 { MaybeObject* maybe_result = DeepCopyBoilerplate(js_object);
160 if (!maybe_result->ToObject(&result)) return maybe_result;
161 }
162 { MaybeObject* maybe_result =
163 copy->SetProperty(key_string, result, NONE);
164 if (!maybe_result->ToObject(&result)) return maybe_result;
165 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000166 }
167 }
168 }
169
170 // Deep copy local elements.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000171 // Pixel elements cannot be created using an object literal.
ager@chromium.org3811b432009-10-28 14:53:37 +0000172 ASSERT(!copy->HasPixelElements() && !copy->HasExternalArrayElements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000173 switch (copy->GetElementsKind()) {
174 case JSObject::FAST_ELEMENTS: {
175 FixedArray* elements = FixedArray::cast(copy->elements());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000176 if (elements->map() == Heap::fixed_cow_array_map()) {
177 Counters::cow_arrays_created_runtime.Increment();
178#ifdef DEBUG
179 for (int i = 0; i < elements->length(); i++) {
180 ASSERT(!elements->get(i)->IsJSObject());
181 }
182#endif
183 } else {
184 for (int i = 0; i < elements->length(); i++) {
185 Object* value = elements->get(i);
186 if (value->IsJSObject()) {
187 JSObject* js_object = JSObject::cast(value);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000188 { MaybeObject* maybe_result = DeepCopyBoilerplate(js_object);
189 if (!maybe_result->ToObject(&result)) return maybe_result;
190 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000191 elements->set(i, result);
192 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000193 }
194 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000195 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000196 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000197 case JSObject::DICTIONARY_ELEMENTS: {
198 NumberDictionary* element_dictionary = copy->element_dictionary();
199 int capacity = element_dictionary->Capacity();
200 for (int i = 0; i < capacity; i++) {
201 Object* k = element_dictionary->KeyAt(i);
202 if (element_dictionary->IsKey(k)) {
203 Object* value = element_dictionary->ValueAt(i);
204 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000205 JSObject* js_object = JSObject::cast(value);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000206 { MaybeObject* maybe_result = DeepCopyBoilerplate(js_object);
207 if (!maybe_result->ToObject(&result)) return maybe_result;
208 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000209 element_dictionary->ValueAtPut(i, result);
210 }
211 }
212 }
213 break;
214 }
215 default:
216 UNREACHABLE();
217 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000218 }
219 return copy;
220}
221
222
lrn@chromium.org303ada72010-10-27 09:33:13 +0000223static MaybeObject* Runtime_CloneLiteralBoilerplate(Arguments args) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000224 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
225 return DeepCopyBoilerplate(boilerplate);
226}
227
228
lrn@chromium.org303ada72010-10-27 09:33:13 +0000229static MaybeObject* Runtime_CloneShallowLiteralBoilerplate(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000230 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000231 return Heap::CopyJSObject(boilerplate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000232}
233
234
ager@chromium.org236ad962008-09-25 09:45:57 +0000235static Handle<Map> ComputeObjectLiteralMap(
236 Handle<Context> context,
237 Handle<FixedArray> constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000238 bool* is_result_from_cache) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000239 int properties_length = constant_properties->length();
240 int number_of_properties = properties_length / 2;
ager@chromium.org236ad962008-09-25 09:45:57 +0000241 if (FLAG_canonicalize_object_literal_maps) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000242 // Check that there are only symbols and array indices among keys.
ager@chromium.org236ad962008-09-25 09:45:57 +0000243 int number_of_symbol_keys = 0;
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000244 for (int p = 0; p != properties_length; p += 2) {
245 Object* key = constant_properties->get(p);
246 uint32_t element_index = 0;
247 if (key->IsSymbol()) {
248 number_of_symbol_keys++;
249 } else if (key->ToArrayIndex(&element_index)) {
250 // An index key does not require space in the property backing store.
251 number_of_properties--;
252 } else {
253 // Bail out as a non-symbol non-index key makes caching impossible.
254 // ASSERT to make sure that the if condition after the loop is false.
255 ASSERT(number_of_symbol_keys != number_of_properties);
256 break;
257 }
ager@chromium.org236ad962008-09-25 09:45:57 +0000258 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000259 // If we only have symbols and array indices among keys then we can
260 // use the map cache in the global context.
ager@chromium.org236ad962008-09-25 09:45:57 +0000261 const int kMaxKeys = 10;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000262 if ((number_of_symbol_keys == number_of_properties) &&
263 (number_of_symbol_keys < kMaxKeys)) {
ager@chromium.org236ad962008-09-25 09:45:57 +0000264 // Create the fixed array with the key.
265 Handle<FixedArray> keys = Factory::NewFixedArray(number_of_symbol_keys);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000266 if (number_of_symbol_keys > 0) {
267 int index = 0;
268 for (int p = 0; p < properties_length; p += 2) {
269 Object* key = constant_properties->get(p);
270 if (key->IsSymbol()) {
271 keys->set(index++, key);
272 }
273 }
274 ASSERT(index == number_of_symbol_keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000275 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000276 *is_result_from_cache = true;
ager@chromium.org236ad962008-09-25 09:45:57 +0000277 return Factory::ObjectLiteralMapFromCache(context, keys);
278 }
279 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000280 *is_result_from_cache = false;
ager@chromium.org32912102009-01-16 10:38:43 +0000281 return Factory::CopyMap(
282 Handle<Map>(context->object_function()->initial_map()),
283 number_of_properties);
ager@chromium.org236ad962008-09-25 09:45:57 +0000284}
285
286
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000287static Handle<Object> CreateLiteralBoilerplate(
288 Handle<FixedArray> literals,
289 Handle<FixedArray> constant_properties);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000290
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000291
292static Handle<Object> CreateObjectLiteralBoilerplate(
293 Handle<FixedArray> literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000294 Handle<FixedArray> constant_properties,
295 bool should_have_fast_elements) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000296 // Get the global context from the literals array. This is the
297 // context in which the function was created and we use the object
298 // function from this context to create the object literal. We do
299 // not use the object function from the current global context
300 // because this might be the object function from another context
301 // which we should not have access to.
ager@chromium.org236ad962008-09-25 09:45:57 +0000302 Handle<Context> context =
303 Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals));
304
305 bool is_result_from_cache;
306 Handle<Map> map = ComputeObjectLiteralMap(context,
307 constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000308 &is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000309
ager@chromium.org236ad962008-09-25 09:45:57 +0000310 Handle<JSObject> boilerplate = Factory::NewJSObjectFromMap(map);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000311
312 // Normalize the elements of the boilerplate to save space if needed.
313 if (!should_have_fast_elements) NormalizeElements(boilerplate);
314
ager@chromium.org32912102009-01-16 10:38:43 +0000315 { // Add the constant properties to the boilerplate.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000316 int length = constant_properties->length();
ager@chromium.org236ad962008-09-25 09:45:57 +0000317 OptimizedObjectForAddingMultipleProperties opt(boilerplate,
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000318 length / 2,
ager@chromium.org236ad962008-09-25 09:45:57 +0000319 !is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000320 for (int index = 0; index < length; index +=2) {
321 Handle<Object> key(constant_properties->get(index+0));
322 Handle<Object> value(constant_properties->get(index+1));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000323 if (value->IsFixedArray()) {
324 // The value contains the constant_properties of a
325 // simple object literal.
326 Handle<FixedArray> array = Handle<FixedArray>::cast(value);
327 value = CreateLiteralBoilerplate(literals, array);
328 if (value.is_null()) return value;
329 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000330 Handle<Object> result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000331 uint32_t element_index = 0;
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000332 if (key->IsSymbol()) {
333 // If key is a symbol it is not an array element.
334 Handle<String> name(String::cast(*key));
335 ASSERT(!name->AsArrayIndex(&element_index));
336 result = SetProperty(boilerplate, name, value, NONE);
337 } else if (key->ToArrayIndex(&element_index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000338 // Array index (uint32).
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000339 result = SetElement(boilerplate, element_index, value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000340 } else {
341 // Non-uint32 number.
342 ASSERT(key->IsNumber());
343 double num = key->Number();
344 char arr[100];
345 Vector<char> buffer(arr, ARRAY_SIZE(arr));
346 const char* str = DoubleToCString(num, buffer);
347 Handle<String> name = Factory::NewStringFromAscii(CStrVector(str));
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000348 result = SetProperty(boilerplate, name, value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000349 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000350 // If setting the property on the boilerplate throws an
351 // exception, the exception is converted to an empty handle in
352 // the handle based operations. In that case, we need to
353 // convert back to an exception.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000354 if (result.is_null()) return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000355 }
356 }
357
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000358 return boilerplate;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000359}
360
361
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000362static Handle<Object> CreateArrayLiteralBoilerplate(
363 Handle<FixedArray> literals,
364 Handle<FixedArray> elements) {
365 // Create the JSArray.
366 Handle<JSFunction> constructor(
367 JSFunction::GlobalContextFromLiterals(*literals)->array_function());
368 Handle<Object> object = Factory::NewJSObject(constructor);
369
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000370 const bool is_cow = (elements->map() == Heap::fixed_cow_array_map());
371 Handle<FixedArray> copied_elements =
372 is_cow ? elements : Factory::CopyFixedArray(elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000373
374 Handle<FixedArray> content = Handle<FixedArray>::cast(copied_elements);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000375 if (is_cow) {
376#ifdef DEBUG
377 // Copy-on-write arrays must be shallow (and simple).
378 for (int i = 0; i < content->length(); i++) {
379 ASSERT(!content->get(i)->IsFixedArray());
380 }
381#endif
382 } else {
383 for (int i = 0; i < content->length(); i++) {
384 if (content->get(i)->IsFixedArray()) {
385 // The value contains the constant_properties of a
386 // simple object literal.
387 Handle<FixedArray> fa(FixedArray::cast(content->get(i)));
388 Handle<Object> result =
389 CreateLiteralBoilerplate(literals, fa);
390 if (result.is_null()) return result;
391 content->set(i, *result);
392 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000393 }
394 }
395
396 // Set the elements.
397 Handle<JSArray>::cast(object)->SetContent(*content);
398 return object;
399}
400
401
402static Handle<Object> CreateLiteralBoilerplate(
403 Handle<FixedArray> literals,
404 Handle<FixedArray> array) {
405 Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
406 switch (CompileTimeValue::GetType(array)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000407 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
408 return CreateObjectLiteralBoilerplate(literals, elements, true);
409 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
410 return CreateObjectLiteralBoilerplate(literals, elements, false);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000411 case CompileTimeValue::ARRAY_LITERAL:
412 return CreateArrayLiteralBoilerplate(literals, elements);
413 default:
414 UNREACHABLE();
415 return Handle<Object>::null();
416 }
417}
418
419
lrn@chromium.org303ada72010-10-27 09:33:13 +0000420static MaybeObject* Runtime_CreateArrayLiteralBoilerplate(Arguments args) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000421 // Takes a FixedArray of elements containing the literal elements of
422 // the array literal and produces JSArray with those elements.
423 // Additionally takes the literals array of the surrounding function
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000424 // which contains the context from which to get the Array function
425 // to use for creating the array literal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000426 HandleScope scope;
427 ASSERT(args.length() == 3);
428 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
429 CONVERT_SMI_CHECKED(literals_index, args[1]);
430 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000431
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000432 Handle<Object> object = CreateArrayLiteralBoilerplate(literals, elements);
433 if (object.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000434
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000435 // Update the functions literal and return the boilerplate.
436 literals->set(literals_index, *object);
437 return *object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000438}
439
440
lrn@chromium.org303ada72010-10-27 09:33:13 +0000441static MaybeObject* Runtime_CreateObjectLiteral(Arguments args) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000442 HandleScope scope;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000443 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000444 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
445 CONVERT_SMI_CHECKED(literals_index, args[1]);
446 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000447 CONVERT_SMI_CHECKED(fast_elements, args[3]);
448 bool should_have_fast_elements = fast_elements == 1;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000449
450 // Check if boilerplate exists. If not, create it first.
451 Handle<Object> boilerplate(literals->get(literals_index));
452 if (*boilerplate == Heap::undefined_value()) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000453 boilerplate = CreateObjectLiteralBoilerplate(literals,
454 constant_properties,
455 should_have_fast_elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000456 if (boilerplate.is_null()) return Failure::Exception();
457 // Update the functions literal and return the boilerplate.
458 literals->set(literals_index, *boilerplate);
459 }
460 return DeepCopyBoilerplate(JSObject::cast(*boilerplate));
461}
462
463
lrn@chromium.org303ada72010-10-27 09:33:13 +0000464static MaybeObject* Runtime_CreateObjectLiteralShallow(Arguments args) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000465 HandleScope scope;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000466 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000467 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
468 CONVERT_SMI_CHECKED(literals_index, args[1]);
469 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000470 CONVERT_SMI_CHECKED(fast_elements, args[3]);
471 bool should_have_fast_elements = fast_elements == 1;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000472
473 // Check if boilerplate exists. If not, create it first.
474 Handle<Object> boilerplate(literals->get(literals_index));
475 if (*boilerplate == Heap::undefined_value()) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000476 boilerplate = CreateObjectLiteralBoilerplate(literals,
477 constant_properties,
478 should_have_fast_elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000479 if (boilerplate.is_null()) return Failure::Exception();
480 // Update the functions literal and return the boilerplate.
481 literals->set(literals_index, *boilerplate);
482 }
483 return Heap::CopyJSObject(JSObject::cast(*boilerplate));
484}
485
486
lrn@chromium.org303ada72010-10-27 09:33:13 +0000487static MaybeObject* Runtime_CreateArrayLiteral(Arguments args) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000488 HandleScope scope;
489 ASSERT(args.length() == 3);
490 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
491 CONVERT_SMI_CHECKED(literals_index, args[1]);
492 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
493
494 // Check if boilerplate exists. If not, create it first.
495 Handle<Object> boilerplate(literals->get(literals_index));
496 if (*boilerplate == Heap::undefined_value()) {
497 boilerplate = CreateArrayLiteralBoilerplate(literals, elements);
498 if (boilerplate.is_null()) return Failure::Exception();
499 // Update the functions literal and return the boilerplate.
500 literals->set(literals_index, *boilerplate);
501 }
502 return DeepCopyBoilerplate(JSObject::cast(*boilerplate));
503}
504
505
lrn@chromium.org303ada72010-10-27 09:33:13 +0000506static MaybeObject* Runtime_CreateArrayLiteralShallow(Arguments args) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000507 HandleScope scope;
508 ASSERT(args.length() == 3);
509 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
510 CONVERT_SMI_CHECKED(literals_index, args[1]);
511 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
512
513 // Check if boilerplate exists. If not, create it first.
514 Handle<Object> boilerplate(literals->get(literals_index));
515 if (*boilerplate == Heap::undefined_value()) {
516 boilerplate = CreateArrayLiteralBoilerplate(literals, elements);
517 if (boilerplate.is_null()) return Failure::Exception();
518 // Update the functions literal and return the boilerplate.
519 literals->set(literals_index, *boilerplate);
520 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000521 if (JSObject::cast(*boilerplate)->elements()->map() ==
522 Heap::fixed_cow_array_map()) {
523 Counters::cow_arrays_created_runtime.Increment();
524 }
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000525 return Heap::CopyJSObject(JSObject::cast(*boilerplate));
526}
527
528
lrn@chromium.org303ada72010-10-27 09:33:13 +0000529static MaybeObject* Runtime_CreateCatchExtensionObject(Arguments args) {
ager@chromium.org32912102009-01-16 10:38:43 +0000530 ASSERT(args.length() == 2);
531 CONVERT_CHECKED(String, key, args[0]);
532 Object* value = args[1];
533 // Create a catch context extension object.
534 JSFunction* constructor =
535 Top::context()->global_context()->context_extension_function();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000536 Object* object;
537 { MaybeObject* maybe_object = Heap::AllocateJSObject(constructor);
538 if (!maybe_object->ToObject(&object)) return maybe_object;
539 }
ager@chromium.org32912102009-01-16 10:38:43 +0000540 // Assign the exception value to the catch variable and make sure
541 // that the catch variable is DontDelete.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000542 { MaybeObject* maybe_value =
543 JSObject::cast(object)->SetProperty(key, value, DONT_DELETE);
544 if (!maybe_value->ToObject(&value)) return maybe_value;
545 }
ager@chromium.org32912102009-01-16 10:38:43 +0000546 return object;
547}
548
549
lrn@chromium.org303ada72010-10-27 09:33:13 +0000550static MaybeObject* Runtime_ClassOf(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000551 NoHandleAllocation ha;
552 ASSERT(args.length() == 1);
553 Object* obj = args[0];
554 if (!obj->IsJSObject()) return Heap::null_value();
555 return JSObject::cast(obj)->class_name();
556}
557
ager@chromium.org7c537e22008-10-16 08:43:32 +0000558
lrn@chromium.org303ada72010-10-27 09:33:13 +0000559static MaybeObject* Runtime_IsInPrototypeChain(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000560 NoHandleAllocation ha;
561 ASSERT(args.length() == 2);
562 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
563 Object* O = args[0];
564 Object* V = args[1];
565 while (true) {
566 Object* prototype = V->GetPrototype();
567 if (prototype->IsNull()) return Heap::false_value();
568 if (O == prototype) return Heap::true_value();
569 V = prototype;
570 }
571}
572
573
ager@chromium.org9085a012009-05-11 19:22:57 +0000574// Inserts an object as the hidden prototype of another object.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000575static MaybeObject* Runtime_SetHiddenPrototype(Arguments args) {
ager@chromium.org9085a012009-05-11 19:22:57 +0000576 NoHandleAllocation ha;
577 ASSERT(args.length() == 2);
578 CONVERT_CHECKED(JSObject, jsobject, args[0]);
579 CONVERT_CHECKED(JSObject, proto, args[1]);
580
581 // Sanity checks. The old prototype (that we are replacing) could
582 // theoretically be null, but if it is not null then check that we
583 // didn't already install a hidden prototype here.
584 RUNTIME_ASSERT(!jsobject->GetPrototype()->IsHeapObject() ||
585 !HeapObject::cast(jsobject->GetPrototype())->map()->is_hidden_prototype());
586 RUNTIME_ASSERT(!proto->map()->is_hidden_prototype());
587
588 // Allocate up front before we start altering state in case we get a GC.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000589 Object* map_or_failure;
590 { MaybeObject* maybe_map_or_failure = proto->map()->CopyDropTransitions();
591 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
592 return maybe_map_or_failure;
593 }
594 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000595 Map* new_proto_map = Map::cast(map_or_failure);
596
lrn@chromium.org303ada72010-10-27 09:33:13 +0000597 { MaybeObject* maybe_map_or_failure = jsobject->map()->CopyDropTransitions();
598 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
599 return maybe_map_or_failure;
600 }
601 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000602 Map* new_map = Map::cast(map_or_failure);
603
604 // Set proto's prototype to be the old prototype of the object.
605 new_proto_map->set_prototype(jsobject->GetPrototype());
606 proto->set_map(new_proto_map);
607 new_proto_map->set_is_hidden_prototype();
608
609 // Set the object's prototype to proto.
610 new_map->set_prototype(proto);
611 jsobject->set_map(new_map);
612
613 return Heap::undefined_value();
614}
615
616
lrn@chromium.org303ada72010-10-27 09:33:13 +0000617static MaybeObject* Runtime_IsConstructCall(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000618 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +0000619 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000620 JavaScriptFrameIterator it;
621 return Heap::ToBoolean(it.frame()->IsConstructor());
622}
623
624
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000625// Recursively traverses hidden prototypes if property is not found
626static void GetOwnPropertyImplementation(JSObject* obj,
627 String* name,
628 LookupResult* result) {
629 obj->LocalLookupRealNamedProperty(name, result);
630
631 if (!result->IsProperty()) {
632 Object* proto = obj->GetPrototype();
633 if (proto->IsJSObject() &&
634 JSObject::cast(proto)->map()->is_hidden_prototype())
635 GetOwnPropertyImplementation(JSObject::cast(proto),
636 name, result);
637 }
638}
639
640
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000641// Enumerator used as indices into the array returned from GetOwnProperty
642enum PropertyDescriptorIndices {
643 IS_ACCESSOR_INDEX,
644 VALUE_INDEX,
645 GETTER_INDEX,
646 SETTER_INDEX,
647 WRITABLE_INDEX,
648 ENUMERABLE_INDEX,
649 CONFIGURABLE_INDEX,
650 DESCRIPTOR_SIZE
651};
652
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000653// Returns an array with the property description:
654// if args[1] is not a property on args[0]
655// returns undefined
656// if args[1] is a data property on args[0]
657// [false, value, Writeable, Enumerable, Configurable]
658// if args[1] is an accessor on args[0]
659// [true, GetFunction, SetFunction, Enumerable, Configurable]
lrn@chromium.org303ada72010-10-27 09:33:13 +0000660static MaybeObject* Runtime_GetOwnProperty(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000661 ASSERT(args.length() == 2);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000662 HandleScope scope;
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000663 Handle<FixedArray> elms = Factory::NewFixedArray(DESCRIPTOR_SIZE);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000664 Handle<JSArray> desc = Factory::NewJSArrayWithElements(elms);
665 LookupResult result;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000666 CONVERT_ARG_CHECKED(JSObject, obj, 0);
667 CONVERT_ARG_CHECKED(String, name, 1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000668
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000669 // This could be an element.
670 uint32_t index;
671 if (name->AsArrayIndex(&index)) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000672 switch (obj->HasLocalElement(index)) {
673 case JSObject::UNDEFINED_ELEMENT:
674 return Heap::undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000675
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000676 case JSObject::STRING_CHARACTER_ELEMENT: {
677 // Special handling of string objects according to ECMAScript 5
678 // 15.5.5.2. Note that this might be a string object with elements
679 // other than the actual string value. This is covered by the
680 // subsequent cases.
681 Handle<JSValue> js_value = Handle<JSValue>::cast(obj);
682 Handle<String> str(String::cast(js_value->value()));
683 Handle<String> substr = SubString(str, index, index+1, NOT_TENURED);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000684
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000685 elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
686 elms->set(VALUE_INDEX, *substr);
687 elms->set(WRITABLE_INDEX, Heap::false_value());
688 elms->set(ENUMERABLE_INDEX, Heap::false_value());
689 elms->set(CONFIGURABLE_INDEX, Heap::false_value());
690 return *desc;
691 }
692
693 case JSObject::INTERCEPTED_ELEMENT:
694 case JSObject::FAST_ELEMENT: {
695 elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
696 Handle<Object> element = GetElement(Handle<Object>(obj), index);
697 elms->set(VALUE_INDEX, *element);
698 elms->set(WRITABLE_INDEX, Heap::true_value());
699 elms->set(ENUMERABLE_INDEX, Heap::true_value());
700 elms->set(CONFIGURABLE_INDEX, Heap::true_value());
701 return *desc;
702 }
703
704 case JSObject::DICTIONARY_ELEMENT: {
705 NumberDictionary* dictionary = obj->element_dictionary();
706 int entry = dictionary->FindEntry(index);
707 ASSERT(entry != NumberDictionary::kNotFound);
708 PropertyDetails details = dictionary->DetailsAt(entry);
709 switch (details.type()) {
710 case CALLBACKS: {
711 // This is an accessor property with getter and/or setter.
712 FixedArray* callbacks =
713 FixedArray::cast(dictionary->ValueAt(entry));
714 elms->set(IS_ACCESSOR_INDEX, Heap::true_value());
715 elms->set(GETTER_INDEX, callbacks->get(0));
716 elms->set(SETTER_INDEX, callbacks->get(1));
717 break;
718 }
719 case NORMAL:
720 // This is a data property.
721 elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
722 elms->set(VALUE_INDEX, dictionary->ValueAt(entry));
723 elms->set(WRITABLE_INDEX, Heap::ToBoolean(!details.IsReadOnly()));
724 break;
725 default:
726 UNREACHABLE();
727 break;
728 }
729 elms->set(ENUMERABLE_INDEX, Heap::ToBoolean(!details.IsDontEnum()));
730 elms->set(CONFIGURABLE_INDEX, Heap::ToBoolean(!details.IsDontDelete()));
731 return *desc;
732 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000733 }
734 }
735
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000736 // Use recursive implementation to also traverse hidden prototypes
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000737 GetOwnPropertyImplementation(*obj, *name, &result);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000738
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000739 if (!result.IsProperty()) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000740 return Heap::undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000741 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000742 if (result.type() == CALLBACKS) {
743 Object* structure = result.GetCallbackObject();
ager@chromium.org5c838252010-02-19 08:53:10 +0000744 if (structure->IsProxy() || structure->IsAccessorInfo()) {
745 // Property that is internally implemented as a callback or
746 // an API defined callback.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000747 Object* value;
748 { MaybeObject* maybe_value = obj->GetPropertyWithCallback(
749 *obj, structure, *name, result.holder());
750 if (!maybe_value->ToObject(&value)) return maybe_value;
751 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000752 elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
753 elms->set(VALUE_INDEX, value);
754 elms->set(WRITABLE_INDEX, Heap::ToBoolean(!result.IsReadOnly()));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000755 } else if (structure->IsFixedArray()) {
756 // __defineGetter__/__defineSetter__ callback.
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000757 elms->set(IS_ACCESSOR_INDEX, Heap::true_value());
758 elms->set(GETTER_INDEX, FixedArray::cast(structure)->get(0));
759 elms->set(SETTER_INDEX, FixedArray::cast(structure)->get(1));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000760 } else {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000761 return Heap::undefined_value();
762 }
763 } else {
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000764 elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
765 elms->set(VALUE_INDEX, result.GetLazyValue());
766 elms->set(WRITABLE_INDEX, Heap::ToBoolean(!result.IsReadOnly()));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000767 }
768
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000769 elms->set(ENUMERABLE_INDEX, Heap::ToBoolean(!result.IsDontEnum()));
770 elms->set(CONFIGURABLE_INDEX, Heap::ToBoolean(!result.IsDontDelete()));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000771 return *desc;
772}
773
774
lrn@chromium.org303ada72010-10-27 09:33:13 +0000775static MaybeObject* Runtime_PreventExtensions(Arguments args) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000776 ASSERT(args.length() == 1);
777 CONVERT_CHECKED(JSObject, obj, args[0]);
778 return obj->PreventExtensions();
779}
780
lrn@chromium.org303ada72010-10-27 09:33:13 +0000781static MaybeObject* Runtime_IsExtensible(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000782 ASSERT(args.length() == 1);
783 CONVERT_CHECKED(JSObject, obj, args[0]);
784 return obj->map()->is_extensible() ? Heap::true_value()
785 : Heap::false_value();
786}
787
788
lrn@chromium.org303ada72010-10-27 09:33:13 +0000789static MaybeObject* Runtime_RegExpCompile(Arguments args) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000790 HandleScope scope;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000791 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000792 CONVERT_ARG_CHECKED(JSRegExp, re, 0);
793 CONVERT_ARG_CHECKED(String, pattern, 1);
794 CONVERT_ARG_CHECKED(String, flags, 2);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000795 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags);
796 if (result.is_null()) return Failure::Exception();
797 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000798}
799
800
lrn@chromium.org303ada72010-10-27 09:33:13 +0000801static MaybeObject* Runtime_CreateApiFunction(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000802 HandleScope scope;
803 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000804 CONVERT_ARG_CHECKED(FunctionTemplateInfo, data, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000805 return *Factory::CreateApiFunction(data);
806}
807
808
lrn@chromium.org303ada72010-10-27 09:33:13 +0000809static MaybeObject* Runtime_IsTemplate(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000810 ASSERT(args.length() == 1);
811 Object* arg = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000812 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000813 return Heap::ToBoolean(result);
814}
815
816
lrn@chromium.org303ada72010-10-27 09:33:13 +0000817static MaybeObject* Runtime_GetTemplateField(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000818 ASSERT(args.length() == 2);
819 CONVERT_CHECKED(HeapObject, templ, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000820 CONVERT_CHECKED(Smi, field, args[1]);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000821 int index = field->value();
822 int offset = index * kPointerSize + HeapObject::kHeaderSize;
823 InstanceType type = templ->map()->instance_type();
824 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
825 type == OBJECT_TEMPLATE_INFO_TYPE);
826 RUNTIME_ASSERT(offset > 0);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000827 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000828 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
829 } else {
830 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
831 }
832 return *HeapObject::RawField(templ, offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000833}
834
835
lrn@chromium.org303ada72010-10-27 09:33:13 +0000836static MaybeObject* Runtime_DisableAccessChecks(Arguments args) {
ager@chromium.org870a0b62008-11-04 11:43:05 +0000837 ASSERT(args.length() == 1);
838 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +0000839 Map* old_map = object->map();
840 bool needs_access_checks = old_map->is_access_check_needed();
841 if (needs_access_checks) {
842 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000843 Object* new_map;
844 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
845 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
846 }
ager@chromium.org32912102009-01-16 10:38:43 +0000847
848 Map::cast(new_map)->set_is_access_check_needed(false);
849 object->set_map(Map::cast(new_map));
850 }
ager@chromium.org870a0b62008-11-04 11:43:05 +0000851 return needs_access_checks ? Heap::true_value() : Heap::false_value();
852}
853
854
lrn@chromium.org303ada72010-10-27 09:33:13 +0000855static MaybeObject* Runtime_EnableAccessChecks(Arguments args) {
ager@chromium.org870a0b62008-11-04 11:43:05 +0000856 ASSERT(args.length() == 1);
857 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +0000858 Map* old_map = object->map();
859 if (!old_map->is_access_check_needed()) {
860 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000861 Object* new_map;
862 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
863 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
864 }
ager@chromium.org32912102009-01-16 10:38:43 +0000865
866 Map::cast(new_map)->set_is_access_check_needed(true);
867 object->set_map(Map::cast(new_map));
868 }
ager@chromium.org870a0b62008-11-04 11:43:05 +0000869 return Heap::undefined_value();
870}
871
872
lrn@chromium.org303ada72010-10-27 09:33:13 +0000873static Failure* ThrowRedeclarationError(const char* type, Handle<String> name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000874 HandleScope scope;
875 Handle<Object> type_handle = Factory::NewStringFromAscii(CStrVector(type));
876 Handle<Object> args[2] = { type_handle, name };
877 Handle<Object> error =
878 Factory::NewTypeError("redeclaration", HandleVector(args, 2));
879 return Top::Throw(*error);
880}
881
882
lrn@chromium.org303ada72010-10-27 09:33:13 +0000883static MaybeObject* Runtime_DeclareGlobals(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000884 HandleScope scope;
885 Handle<GlobalObject> global = Handle<GlobalObject>(Top::context()->global());
886
ager@chromium.org3811b432009-10-28 14:53:37 +0000887 Handle<Context> context = args.at<Context>(0);
888 CONVERT_ARG_CHECKED(FixedArray, pairs, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000889 bool is_eval = Smi::cast(args[2])->value() == 1;
890
891 // Compute the property attributes. According to ECMA-262, section
892 // 13, page 71, the property must be read-only and
893 // non-deletable. However, neither SpiderMonkey nor KJS creates the
894 // property as read-only, so we don't either.
895 PropertyAttributes base = is_eval ? NONE : DONT_DELETE;
896
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000897 // Traverse the name/value pairs and set the properties.
898 int length = pairs->length();
899 for (int i = 0; i < length; i += 2) {
900 HandleScope scope;
901 Handle<String> name(String::cast(pairs->get(i)));
902 Handle<Object> value(pairs->get(i + 1));
903
904 // We have to declare a global const property. To capture we only
905 // assign to it when evaluating the assignment for "const x =
906 // <expr>" the initial value is the hole.
907 bool is_const_property = value->IsTheHole();
908
909 if (value->IsUndefined() || is_const_property) {
910 // Lookup the property in the global object, and don't set the
911 // value of the variable if the property is already there.
912 LookupResult lookup;
913 global->Lookup(*name, &lookup);
914 if (lookup.IsProperty()) {
915 // Determine if the property is local by comparing the holder
916 // against the global object. The information will be used to
917 // avoid throwing re-declaration errors when declaring
918 // variables or constants that exist in the prototype chain.
919 bool is_local = (*global == lookup.holder());
920 // Get the property attributes and determine if the property is
921 // read-only.
922 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
923 bool is_read_only = (attributes & READ_ONLY) != 0;
924 if (lookup.type() == INTERCEPTOR) {
925 // If the interceptor says the property is there, we
926 // just return undefined without overwriting the property.
927 // Otherwise, we continue to setting the property.
928 if (attributes != ABSENT) {
929 // Check if the existing property conflicts with regards to const.
930 if (is_local && (is_read_only || is_const_property)) {
931 const char* type = (is_read_only) ? "const" : "var";
932 return ThrowRedeclarationError(type, name);
933 };
934 // The property already exists without conflicting: Go to
935 // the next declaration.
936 continue;
937 }
938 // Fall-through and introduce the absent property by using
939 // SetProperty.
940 } else {
941 if (is_local && (is_read_only || is_const_property)) {
942 const char* type = (is_read_only) ? "const" : "var";
943 return ThrowRedeclarationError(type, name);
944 }
945 // The property already exists without conflicting: Go to
946 // the next declaration.
947 continue;
948 }
949 }
950 } else {
951 // Copy the function and update its context. Use it as value.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000952 Handle<SharedFunctionInfo> shared =
953 Handle<SharedFunctionInfo>::cast(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000954 Handle<JSFunction> function =
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000955 Factory::NewFunctionFromSharedFunctionInfo(shared, context, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000956 value = function;
957 }
958
959 LookupResult lookup;
960 global->LocalLookup(*name, &lookup);
961
962 PropertyAttributes attributes = is_const_property
963 ? static_cast<PropertyAttributes>(base | READ_ONLY)
964 : base;
965
966 if (lookup.IsProperty()) {
967 // There's a local property that we need to overwrite because
968 // we're either declaring a function or there's an interceptor
969 // that claims the property is absent.
970
971 // Check for conflicting re-declarations. We cannot have
972 // conflicting types in case of intercepted properties because
973 // they are absent.
974 if (lookup.type() != INTERCEPTOR &&
975 (lookup.IsReadOnly() || is_const_property)) {
976 const char* type = (lookup.IsReadOnly()) ? "const" : "var";
977 return ThrowRedeclarationError(type, name);
978 }
979 SetProperty(global, name, value, attributes);
980 } else {
981 // If a property with this name does not already exist on the
982 // global object add the property locally. We take special
983 // precautions to always add it as a local property even in case
984 // of callbacks in the prototype chain (this rules out using
985 // SetProperty). Also, we must use the handle-based version to
986 // avoid GC issues.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000987 IgnoreAttributesAndSetLocalProperty(global, name, value, attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000988 }
989 }
ager@chromium.org7c537e22008-10-16 08:43:32 +0000990
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000991 return Heap::undefined_value();
992}
993
994
lrn@chromium.org303ada72010-10-27 09:33:13 +0000995static MaybeObject* Runtime_DeclareContextSlot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000996 HandleScope scope;
ager@chromium.org7c537e22008-10-16 08:43:32 +0000997 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000998
ager@chromium.org7c537e22008-10-16 08:43:32 +0000999 CONVERT_ARG_CHECKED(Context, context, 0);
1000 Handle<String> name(String::cast(args[1]));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001001 PropertyAttributes mode =
ager@chromium.org7c537e22008-10-16 08:43:32 +00001002 static_cast<PropertyAttributes>(Smi::cast(args[2])->value());
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001003 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001004 Handle<Object> initial_value(args[3]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001005
1006 // Declarations are always done in the function context.
1007 context = Handle<Context>(context->fcontext());
1008
1009 int index;
1010 PropertyAttributes attributes;
1011 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001012 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001013 context->Lookup(name, flags, &index, &attributes);
1014
1015 if (attributes != ABSENT) {
1016 // The name was declared before; check for conflicting
1017 // re-declarations: This is similar to the code in parser.cc in
1018 // the AstBuildingParser::Declare function.
1019 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
1020 // Functions are not read-only.
1021 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
1022 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
1023 return ThrowRedeclarationError(type, name);
1024 }
1025
1026 // Initialize it if necessary.
1027 if (*initial_value != NULL) {
1028 if (index >= 0) {
1029 // The variable or constant context slot should always be in
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001030 // the function context or the arguments object.
1031 if (holder->IsContext()) {
1032 ASSERT(holder.is_identical_to(context));
1033 if (((attributes & READ_ONLY) == 0) ||
1034 context->get(index)->IsTheHole()) {
1035 context->set(index, *initial_value);
1036 }
1037 } else {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001038 // The holder is an arguments object.
1039 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
1040 SetElement(arguments, index, initial_value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001041 }
1042 } else {
1043 // Slow case: The property is not in the FixedArray part of the context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001044 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001045 SetProperty(context_ext, name, initial_value, mode);
1046 }
1047 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001048
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001049 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001050 // The property is not in the function context. It needs to be
1051 // "declared" in the function context's extension context, or in the
1052 // global context.
1053 Handle<JSObject> context_ext;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001054 if (context->has_extension()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001055 // The function context's extension context exists - use it.
1056 context_ext = Handle<JSObject>(context->extension());
1057 } else {
1058 // The function context's extension context does not exists - allocate
1059 // it.
1060 context_ext = Factory::NewJSObject(Top::context_extension_function());
1061 // And store it in the extension slot.
1062 context->set_extension(*context_ext);
1063 }
1064 ASSERT(*context_ext != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001065
ager@chromium.org7c537e22008-10-16 08:43:32 +00001066 // Declare the property by setting it to the initial value if provided,
1067 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
1068 // constant declarations).
1069 ASSERT(!context_ext->HasLocalProperty(*name));
1070 Handle<Object> value(Heap::undefined_value());
1071 if (*initial_value != NULL) value = initial_value;
1072 SetProperty(context_ext, name, value, mode);
1073 ASSERT(context_ext->GetLocalPropertyAttribute(*name) == mode);
1074 }
1075
1076 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001077}
1078
1079
lrn@chromium.org303ada72010-10-27 09:33:13 +00001080static MaybeObject* Runtime_InitializeVarGlobal(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001081 NoHandleAllocation nha;
1082
1083 // Determine if we need to assign to the variable if it already
1084 // exists (based on the number of arguments).
1085 RUNTIME_ASSERT(args.length() == 1 || args.length() == 2);
1086 bool assign = args.length() == 2;
1087
1088 CONVERT_ARG_CHECKED(String, name, 0);
1089 GlobalObject* global = Top::context()->global();
1090
1091 // According to ECMA-262, section 12.2, page 62, the property must
1092 // not be deletable.
1093 PropertyAttributes attributes = DONT_DELETE;
1094
1095 // Lookup the property locally in the global object. If it isn't
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001096 // there, there is a property with this name in the prototype chain.
1097 // We follow Safari and Firefox behavior and only set the property
1098 // locally if there is an explicit initialization value that we have
1099 // to assign to the property. When adding the property we take
1100 // special precautions to always add it as a local property even in
1101 // case of callbacks in the prototype chain (this rules out using
1102 // SetProperty). We have IgnoreAttributesAndSetLocalProperty for
1103 // this.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001104 // Note that objects can have hidden prototypes, so we need to traverse
1105 // the whole chain of hidden prototypes to do a 'local' lookup.
1106 JSObject* real_holder = global;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001107 LookupResult lookup;
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001108 while (true) {
1109 real_holder->LocalLookup(*name, &lookup);
1110 if (lookup.IsProperty()) {
1111 // Determine if this is a redeclaration of something read-only.
1112 if (lookup.IsReadOnly()) {
1113 // If we found readonly property on one of hidden prototypes,
1114 // just shadow it.
1115 if (real_holder != Top::context()->global()) break;
1116 return ThrowRedeclarationError("const", name);
1117 }
1118
1119 // Determine if this is a redeclaration of an intercepted read-only
1120 // property and figure out if the property exists at all.
1121 bool found = true;
1122 PropertyType type = lookup.type();
1123 if (type == INTERCEPTOR) {
1124 HandleScope handle_scope;
1125 Handle<JSObject> holder(real_holder);
1126 PropertyAttributes intercepted = holder->GetPropertyAttribute(*name);
1127 real_holder = *holder;
1128 if (intercepted == ABSENT) {
1129 // The interceptor claims the property isn't there. We need to
1130 // make sure to introduce it.
1131 found = false;
1132 } else if ((intercepted & READ_ONLY) != 0) {
1133 // The property is present, but read-only. Since we're trying to
1134 // overwrite it with a variable declaration we must throw a
1135 // re-declaration error. However if we found readonly property
1136 // on one of hidden prototypes, just shadow it.
1137 if (real_holder != Top::context()->global()) break;
1138 return ThrowRedeclarationError("const", name);
1139 }
1140 }
1141
1142 if (found && !assign) {
1143 // The global property is there and we're not assigning any value
1144 // to it. Just return.
1145 return Heap::undefined_value();
1146 }
1147
1148 // Assign the value (or undefined) to the property.
1149 Object* value = (assign) ? args[1] : Heap::undefined_value();
1150 return real_holder->SetProperty(&lookup, *name, value, attributes);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001151 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001152
1153 Object* proto = real_holder->GetPrototype();
1154 if (!proto->IsJSObject())
1155 break;
1156
1157 if (!JSObject::cast(proto)->map()->is_hidden_prototype())
1158 break;
1159
1160 real_holder = JSObject::cast(proto);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001161 }
1162
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001163 global = Top::context()->global();
1164 if (assign) {
1165 return global->IgnoreAttributesAndSetLocalProperty(*name,
1166 args[1],
1167 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001168 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001169 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001170}
1171
1172
lrn@chromium.org303ada72010-10-27 09:33:13 +00001173static MaybeObject* Runtime_InitializeConstGlobal(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001174 // All constants are declared with an initial value. The name
1175 // of the constant is the first argument and the initial value
1176 // is the second.
1177 RUNTIME_ASSERT(args.length() == 2);
1178 CONVERT_ARG_CHECKED(String, name, 0);
1179 Handle<Object> value = args.at<Object>(1);
1180
1181 // Get the current global object from top.
1182 GlobalObject* global = Top::context()->global();
1183
1184 // According to ECMA-262, section 12.2, page 62, the property must
1185 // not be deletable. Since it's a const, it must be READ_ONLY too.
1186 PropertyAttributes attributes =
1187 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
1188
1189 // Lookup the property locally in the global object. If it isn't
1190 // there, we add the property and take special precautions to always
1191 // add it as a local property even in case of callbacks in the
1192 // prototype chain (this rules out using SetProperty).
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001193 // We use IgnoreAttributesAndSetLocalProperty instead
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001194 LookupResult lookup;
1195 global->LocalLookup(*name, &lookup);
1196 if (!lookup.IsProperty()) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001197 return global->IgnoreAttributesAndSetLocalProperty(*name,
1198 *value,
1199 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001200 }
1201
1202 // Determine if this is a redeclaration of something not
1203 // read-only. In case the result is hidden behind an interceptor we
1204 // need to ask it for the property attributes.
1205 if (!lookup.IsReadOnly()) {
1206 if (lookup.type() != INTERCEPTOR) {
1207 return ThrowRedeclarationError("var", name);
1208 }
1209
1210 PropertyAttributes intercepted = global->GetPropertyAttribute(*name);
1211
1212 // Throw re-declaration error if the intercepted property is present
1213 // but not read-only.
1214 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
1215 return ThrowRedeclarationError("var", name);
1216 }
1217
1218 // Restore global object from context (in case of GC) and continue
1219 // with setting the value because the property is either absent or
1220 // read-only. We also have to do redo the lookup.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001221 HandleScope handle_scope;
1222 Handle<GlobalObject>global(Top::context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001223
1224 // BUG 1213579: Handle the case where we have to set a read-only
1225 // property through an interceptor and only do it if it's
1226 // uninitialized, e.g. the hole. Nirk...
lrn@chromium.org303ada72010-10-27 09:33:13 +00001227 SetProperty(global, name, value, attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001228 return *value;
1229 }
1230
1231 // Set the value, but only we're assigning the initial value to a
1232 // constant. For now, we determine this by checking if the
1233 // current value is the hole.
1234 PropertyType type = lookup.type();
1235 if (type == FIELD) {
1236 FixedArray* properties = global->properties();
1237 int index = lookup.GetFieldIndex();
1238 if (properties->get(index)->IsTheHole()) {
1239 properties->set(index, *value);
1240 }
1241 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001242 if (global->GetNormalizedProperty(&lookup)->IsTheHole()) {
1243 global->SetNormalizedProperty(&lookup, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001244 }
1245 } else {
1246 // Ignore re-initialization of constants that have already been
1247 // assigned a function value.
1248 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
1249 }
1250
1251 // Use the set value as the result of the operation.
1252 return *value;
1253}
1254
1255
lrn@chromium.org303ada72010-10-27 09:33:13 +00001256static MaybeObject* Runtime_InitializeConstContextSlot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001257 HandleScope scope;
1258 ASSERT(args.length() == 3);
1259
1260 Handle<Object> value(args[0]);
1261 ASSERT(!value->IsTheHole());
1262 CONVERT_ARG_CHECKED(Context, context, 1);
1263 Handle<String> name(String::cast(args[2]));
1264
1265 // Initializations are always done in the function context.
1266 context = Handle<Context>(context->fcontext());
1267
1268 int index;
1269 PropertyAttributes attributes;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001270 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001271 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001272 context->Lookup(name, flags, &index, &attributes);
1273
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001274 // In most situations, the property introduced by the const
1275 // declaration should be present in the context extension object.
1276 // However, because declaration and initialization are separate, the
1277 // property might have been deleted (if it was introduced by eval)
1278 // before we reach the initialization point.
1279 //
1280 // Example:
1281 //
1282 // function f() { eval("delete x; const x;"); }
1283 //
1284 // In that case, the initialization behaves like a normal assignment
1285 // to property 'x'.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001286 if (index >= 0) {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001287 // Property was found in a context.
1288 if (holder->IsContext()) {
1289 // The holder cannot be the function context. If it is, there
1290 // should have been a const redeclaration error when declaring
1291 // the const property.
1292 ASSERT(!holder.is_identical_to(context));
1293 if ((attributes & READ_ONLY) == 0) {
1294 Handle<Context>::cast(holder)->set(index, *value);
1295 }
1296 } else {
1297 // The holder is an arguments object.
1298 ASSERT((attributes & READ_ONLY) == 0);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001299 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
1300 SetElement(arguments, index, value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001301 }
1302 return *value;
1303 }
1304
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001305 // The property could not be found, we introduce it in the global
1306 // context.
1307 if (attributes == ABSENT) {
1308 Handle<JSObject> global = Handle<JSObject>(Top::context()->global());
1309 SetProperty(global, name, value, NONE);
1310 return *value;
1311 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001312
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001313 // The property was present in a context extension object.
1314 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001315
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001316 if (*context_ext == context->extension()) {
1317 // This is the property that was introduced by the const
1318 // declaration. Set it if it hasn't been set before. NOTE: We
1319 // cannot use GetProperty() to get the current value as it
1320 // 'unholes' the value.
1321 LookupResult lookup;
1322 context_ext->LocalLookupRealNamedProperty(*name, &lookup);
1323 ASSERT(lookup.IsProperty()); // the property was declared
1324 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
1325
1326 PropertyType type = lookup.type();
1327 if (type == FIELD) {
1328 FixedArray* properties = context_ext->properties();
1329 int index = lookup.GetFieldIndex();
1330 if (properties->get(index)->IsTheHole()) {
1331 properties->set(index, *value);
1332 }
1333 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001334 if (context_ext->GetNormalizedProperty(&lookup)->IsTheHole()) {
1335 context_ext->SetNormalizedProperty(&lookup, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001336 }
1337 } else {
1338 // We should not reach here. Any real, named property should be
1339 // either a field or a dictionary slot.
1340 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001341 }
1342 } else {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001343 // The property was found in a different context extension object.
1344 // Set it if it is not a read-only property.
1345 if ((attributes & READ_ONLY) == 0) {
1346 Handle<Object> set = SetProperty(context_ext, name, value, attributes);
1347 // Setting a property might throw an exception. Exceptions
1348 // are converted to empty handles in handle operations. We
1349 // need to convert back to exceptions here.
1350 if (set.is_null()) {
1351 ASSERT(Top::has_pending_exception());
1352 return Failure::Exception();
1353 }
1354 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001355 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001356
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001357 return *value;
1358}
1359
1360
lrn@chromium.org303ada72010-10-27 09:33:13 +00001361static MaybeObject* Runtime_OptimizeObjectForAddingMultipleProperties(
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001362 Arguments args) {
1363 HandleScope scope;
1364 ASSERT(args.length() == 2);
1365 CONVERT_ARG_CHECKED(JSObject, object, 0);
1366 CONVERT_SMI_CHECKED(properties, args[1]);
1367 if (object->HasFastProperties()) {
1368 NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
1369 }
1370 return *object;
1371}
1372
1373
lrn@chromium.org303ada72010-10-27 09:33:13 +00001374static MaybeObject* Runtime_RegExpExec(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001375 HandleScope scope;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001376 ASSERT(args.length() == 4);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001377 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
1378 CONVERT_ARG_CHECKED(String, subject, 1);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001379 // Due to the way the JS calls are constructed this must be less than the
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001380 // length of a string, i.e. it is always a Smi. We check anyway for security.
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001381 CONVERT_SMI_CHECKED(index, args[2]);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001382 CONVERT_ARG_CHECKED(JSArray, last_match_info, 3);
ager@chromium.org41826e72009-03-30 13:30:57 +00001383 RUNTIME_ASSERT(last_match_info->HasFastElements());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001384 RUNTIME_ASSERT(index >= 0);
1385 RUNTIME_ASSERT(index <= subject->length());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001386 Counters::regexp_entry_runtime.Increment();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001387 Handle<Object> result = RegExpImpl::Exec(regexp,
1388 subject,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001389 index,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001390 last_match_info);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001391 if (result.is_null()) return Failure::Exception();
1392 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001393}
1394
1395
lrn@chromium.org303ada72010-10-27 09:33:13 +00001396static MaybeObject* Runtime_RegExpConstructResult(Arguments args) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001397 ASSERT(args.length() == 3);
1398 CONVERT_SMI_CHECKED(elements_count, args[0]);
1399 if (elements_count > JSArray::kMaxFastElementsLength) {
1400 return Top::ThrowIllegalOperation();
1401 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00001402 Object* new_object;
1403 { MaybeObject* maybe_new_object =
1404 Heap::AllocateFixedArrayWithHoles(elements_count);
1405 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1406 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001407 FixedArray* elements = FixedArray::cast(new_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001408 { MaybeObject* maybe_new_object = Heap::AllocateRaw(JSRegExpResult::kSize,
1409 NEW_SPACE,
1410 OLD_POINTER_SPACE);
1411 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1412 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001413 {
1414 AssertNoAllocation no_gc;
1415 HandleScope scope;
1416 reinterpret_cast<HeapObject*>(new_object)->
1417 set_map(Top::global_context()->regexp_result_map());
1418 }
1419 JSArray* array = JSArray::cast(new_object);
1420 array->set_properties(Heap::empty_fixed_array());
1421 array->set_elements(elements);
1422 array->set_length(Smi::FromInt(elements_count));
1423 // Write in-object properties after the length of the array.
1424 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]);
1425 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]);
1426 return array;
1427}
1428
1429
lrn@chromium.org303ada72010-10-27 09:33:13 +00001430static MaybeObject* Runtime_RegExpInitializeObject(Arguments args) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00001431 AssertNoAllocation no_alloc;
1432 ASSERT(args.length() == 5);
1433 CONVERT_CHECKED(JSRegExp, regexp, args[0]);
1434 CONVERT_CHECKED(String, source, args[1]);
1435
1436 Object* global = args[2];
1437 if (!global->IsTrue()) global = Heap::false_value();
1438
1439 Object* ignoreCase = args[3];
1440 if (!ignoreCase->IsTrue()) ignoreCase = Heap::false_value();
1441
1442 Object* multiline = args[4];
1443 if (!multiline->IsTrue()) multiline = Heap::false_value();
1444
1445 Map* map = regexp->map();
1446 Object* constructor = map->constructor();
1447 if (constructor->IsJSFunction() &&
1448 JSFunction::cast(constructor)->initial_map() == map) {
1449 // If we still have the original map, set in-object properties directly.
1450 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source);
1451 // TODO(lrn): Consider skipping write barrier on booleans as well.
1452 // Both true and false should be in oldspace at all times.
1453 regexp->InObjectPropertyAtPut(JSRegExp::kGlobalFieldIndex, global);
1454 regexp->InObjectPropertyAtPut(JSRegExp::kIgnoreCaseFieldIndex, ignoreCase);
1455 regexp->InObjectPropertyAtPut(JSRegExp::kMultilineFieldIndex, multiline);
1456 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
1457 Smi::FromInt(0),
1458 SKIP_WRITE_BARRIER);
1459 return regexp;
1460 }
1461
lrn@chromium.org303ada72010-10-27 09:33:13 +00001462 // Map has changed, so use generic, but slower, method. Since these
1463 // properties were all added as DONT_DELETE they must be present and
1464 // normal so no failures can be expected.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001465 PropertyAttributes final =
1466 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
1467 PropertyAttributes writable =
1468 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001469 MaybeObject* result;
1470 result = regexp->IgnoreAttributesAndSetLocalProperty(Heap::source_symbol(),
1471 source,
1472 final);
1473 ASSERT(!result->IsFailure());
1474 result = regexp->IgnoreAttributesAndSetLocalProperty(Heap::global_symbol(),
1475 global,
1476 final);
1477 ASSERT(!result->IsFailure());
1478 result =
1479 regexp->IgnoreAttributesAndSetLocalProperty(Heap::ignore_case_symbol(),
1480 ignoreCase,
1481 final);
1482 ASSERT(!result->IsFailure());
1483 result = regexp->IgnoreAttributesAndSetLocalProperty(Heap::multiline_symbol(),
1484 multiline,
1485 final);
1486 ASSERT(!result->IsFailure());
1487 result =
1488 regexp->IgnoreAttributesAndSetLocalProperty(Heap::last_index_symbol(),
1489 Smi::FromInt(0),
1490 writable);
1491 ASSERT(!result->IsFailure());
1492 USE(result);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001493 return regexp;
1494}
1495
1496
lrn@chromium.org303ada72010-10-27 09:33:13 +00001497static MaybeObject* Runtime_FinishArrayPrototypeSetup(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001498 HandleScope scope;
1499 ASSERT(args.length() == 1);
1500 CONVERT_ARG_CHECKED(JSArray, prototype, 0);
1501 // This is necessary to enable fast checks for absence of elements
1502 // on Array.prototype and below.
1503 prototype->set_elements(Heap::empty_fixed_array());
1504 return Smi::FromInt(0);
1505}
1506
1507
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001508static Handle<JSFunction> InstallBuiltin(Handle<JSObject> holder,
1509 const char* name,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001510 Builtins::Name builtin_name) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001511 Handle<String> key = Factory::LookupAsciiSymbol(name);
1512 Handle<Code> code(Builtins::builtin(builtin_name));
1513 Handle<JSFunction> optimized = Factory::NewFunction(key,
1514 JS_OBJECT_TYPE,
1515 JSObject::kHeaderSize,
1516 code,
1517 false);
1518 optimized->shared()->DontAdaptArguments();
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001519 SetProperty(holder, key, optimized, NONE);
1520 return optimized;
1521}
1522
1523
lrn@chromium.org303ada72010-10-27 09:33:13 +00001524static MaybeObject* Runtime_SpecialArrayFunctions(Arguments args) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001525 HandleScope scope;
1526 ASSERT(args.length() == 1);
1527 CONVERT_ARG_CHECKED(JSObject, holder, 0);
1528
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001529 InstallBuiltin(holder, "pop", Builtins::ArrayPop);
1530 InstallBuiltin(holder, "push", Builtins::ArrayPush);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001531 InstallBuiltin(holder, "shift", Builtins::ArrayShift);
1532 InstallBuiltin(holder, "unshift", Builtins::ArrayUnshift);
1533 InstallBuiltin(holder, "slice", Builtins::ArraySlice);
1534 InstallBuiltin(holder, "splice", Builtins::ArraySplice);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001535 InstallBuiltin(holder, "concat", Builtins::ArrayConcat);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001536
1537 return *holder;
1538}
1539
1540
lrn@chromium.org303ada72010-10-27 09:33:13 +00001541static MaybeObject* Runtime_GetGlobalReceiver(Arguments args) {
ager@chromium.org357bf652010-04-12 11:30:10 +00001542 // Returns a real global receiver, not one of builtins object.
1543 Context* global_context = Top::context()->global()->global_context();
1544 return global_context->global()->global_receiver();
1545}
1546
1547
lrn@chromium.org303ada72010-10-27 09:33:13 +00001548static MaybeObject* Runtime_MaterializeRegExpLiteral(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001549 HandleScope scope;
1550 ASSERT(args.length() == 4);
1551 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
1552 int index = Smi::cast(args[1])->value();
1553 Handle<String> pattern = args.at<String>(2);
1554 Handle<String> flags = args.at<String>(3);
1555
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001556 // Get the RegExp function from the context in the literals array.
1557 // This is the RegExp function from the context in which the
1558 // function was created. We do not use the RegExp function from the
1559 // current global context because this might be the RegExp function
1560 // from another context which we should not have access to.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001561 Handle<JSFunction> constructor =
ager@chromium.org236ad962008-09-25 09:45:57 +00001562 Handle<JSFunction>(
1563 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001564 // Compute the regular expression literal.
1565 bool has_pending_exception;
1566 Handle<Object> regexp =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001567 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
1568 &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001569 if (has_pending_exception) {
1570 ASSERT(Top::has_pending_exception());
1571 return Failure::Exception();
1572 }
1573 literals->set(index, *regexp);
1574 return *regexp;
1575}
1576
1577
lrn@chromium.org303ada72010-10-27 09:33:13 +00001578static MaybeObject* Runtime_FunctionGetName(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001579 NoHandleAllocation ha;
1580 ASSERT(args.length() == 1);
1581
1582 CONVERT_CHECKED(JSFunction, f, args[0]);
1583 return f->shared()->name();
1584}
1585
1586
lrn@chromium.org303ada72010-10-27 09:33:13 +00001587static MaybeObject* Runtime_FunctionSetName(Arguments args) {
ager@chromium.org236ad962008-09-25 09:45:57 +00001588 NoHandleAllocation ha;
1589 ASSERT(args.length() == 2);
1590
1591 CONVERT_CHECKED(JSFunction, f, args[0]);
1592 CONVERT_CHECKED(String, name, args[1]);
1593 f->shared()->set_name(name);
1594 return Heap::undefined_value();
1595}
1596
1597
lrn@chromium.org303ada72010-10-27 09:33:13 +00001598static MaybeObject* Runtime_FunctionRemovePrototype(Arguments args) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001599 NoHandleAllocation ha;
1600 ASSERT(args.length() == 1);
1601
1602 CONVERT_CHECKED(JSFunction, f, args[0]);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001603 Object* obj;
1604 { MaybeObject* maybe_obj = f->RemovePrototype();
1605 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1606 }
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001607
1608 return Heap::undefined_value();
1609}
1610
1611
lrn@chromium.org303ada72010-10-27 09:33:13 +00001612static MaybeObject* Runtime_FunctionGetScript(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001613 HandleScope scope;
1614 ASSERT(args.length() == 1);
1615
1616 CONVERT_CHECKED(JSFunction, fun, args[0]);
1617 Handle<Object> script = Handle<Object>(fun->shared()->script());
1618 if (!script->IsScript()) return Heap::undefined_value();
1619
1620 return *GetScriptWrapper(Handle<Script>::cast(script));
1621}
1622
1623
lrn@chromium.org303ada72010-10-27 09:33:13 +00001624static MaybeObject* Runtime_FunctionGetSourceCode(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001625 NoHandleAllocation ha;
1626 ASSERT(args.length() == 1);
1627
1628 CONVERT_CHECKED(JSFunction, f, args[0]);
1629 return f->shared()->GetSourceCode();
1630}
1631
1632
lrn@chromium.org303ada72010-10-27 09:33:13 +00001633static MaybeObject* Runtime_FunctionGetScriptSourcePosition(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001634 NoHandleAllocation ha;
1635 ASSERT(args.length() == 1);
1636
1637 CONVERT_CHECKED(JSFunction, fun, args[0]);
1638 int pos = fun->shared()->start_position();
1639 return Smi::FromInt(pos);
1640}
1641
1642
lrn@chromium.org303ada72010-10-27 09:33:13 +00001643static MaybeObject* Runtime_FunctionGetPositionForOffset(Arguments args) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001644 ASSERT(args.length() == 2);
1645
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001646 CONVERT_CHECKED(Code, code, args[0]);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001647 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
1648
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001649 RUNTIME_ASSERT(0 <= offset && offset < code->Size());
1650
1651 Address pc = code->address() + offset;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001652 return Smi::FromInt(code->SourcePosition(pc));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001653}
1654
1655
1656
lrn@chromium.org303ada72010-10-27 09:33:13 +00001657static MaybeObject* Runtime_FunctionSetInstanceClassName(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001658 NoHandleAllocation ha;
1659 ASSERT(args.length() == 2);
1660
1661 CONVERT_CHECKED(JSFunction, fun, args[0]);
1662 CONVERT_CHECKED(String, name, args[1]);
1663 fun->SetInstanceClassName(name);
1664 return Heap::undefined_value();
1665}
1666
1667
lrn@chromium.org303ada72010-10-27 09:33:13 +00001668static MaybeObject* Runtime_FunctionSetLength(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001669 NoHandleAllocation ha;
1670 ASSERT(args.length() == 2);
1671
1672 CONVERT_CHECKED(JSFunction, fun, args[0]);
1673 CONVERT_CHECKED(Smi, length, args[1]);
1674 fun->shared()->set_length(length->value());
1675 return length;
1676}
1677
1678
lrn@chromium.org303ada72010-10-27 09:33:13 +00001679static MaybeObject* Runtime_FunctionSetPrototype(Arguments args) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001680 NoHandleAllocation ha;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001681 ASSERT(args.length() == 2);
1682
1683 CONVERT_CHECKED(JSFunction, fun, args[0]);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001684 ASSERT(fun->should_have_prototype());
lrn@chromium.org303ada72010-10-27 09:33:13 +00001685 Object* obj;
1686 { MaybeObject* maybe_obj =
1687 Accessors::FunctionSetPrototype(fun, args[1], NULL);
1688 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1689 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001690 return args[0]; // return TOS
1691}
1692
1693
lrn@chromium.org303ada72010-10-27 09:33:13 +00001694static MaybeObject* Runtime_FunctionIsAPIFunction(Arguments args) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001695 NoHandleAllocation ha;
1696 ASSERT(args.length() == 1);
1697
1698 CONVERT_CHECKED(JSFunction, f, args[0]);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001699 return f->shared()->IsApiFunction() ? Heap::true_value()
1700 : Heap::false_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001701}
1702
lrn@chromium.org303ada72010-10-27 09:33:13 +00001703static MaybeObject* Runtime_FunctionIsBuiltin(Arguments args) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001704 NoHandleAllocation ha;
1705 ASSERT(args.length() == 1);
1706
1707 CONVERT_CHECKED(JSFunction, f, args[0]);
1708 return f->IsBuiltin() ? Heap::true_value() : Heap::false_value();
1709}
1710
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001711
lrn@chromium.org303ada72010-10-27 09:33:13 +00001712static MaybeObject* Runtime_SetCode(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001713 HandleScope scope;
1714 ASSERT(args.length() == 2);
1715
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001716 CONVERT_ARG_CHECKED(JSFunction, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001717 Handle<Object> code = args.at<Object>(1);
1718
1719 Handle<Context> context(target->context());
1720
1721 if (!code->IsNull()) {
1722 RUNTIME_ASSERT(code->IsJSFunction());
1723 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001724 Handle<SharedFunctionInfo> shared(fun->shared());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001725
1726 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001727 return Failure::Exception();
1728 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001729 // Since we don't store the source for this we should never
1730 // optimize this.
1731 shared->code()->set_optimizable(false);
1732
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001733 // Set the code, scope info, formal parameter count,
1734 // and the length of the target function.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00001735 target->shared()->set_code(shared->code());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001736 target->ReplaceCode(shared->code());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001737 target->shared()->set_scope_info(shared->scope_info());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001738 target->shared()->set_length(shared->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001739 target->shared()->set_formal_parameter_count(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001740 shared->formal_parameter_count());
ager@chromium.org7c537e22008-10-16 08:43:32 +00001741 // Set the source code of the target function to undefined.
1742 // SetCode is only used for built-in constructors like String,
1743 // Array, and Object, and some web code
1744 // doesn't like seeing source code for constructors.
1745 target->shared()->set_script(Heap::undefined_value());
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001746 // Clear the optimization hints related to the compiled code as these are no
1747 // longer valid when the code is overwritten.
1748 target->shared()->ClearThisPropertyAssignmentsInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001749 context = Handle<Context>(fun->context());
1750
1751 // Make sure we get a fresh copy of the literal vector to avoid
1752 // cross context contamination.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001753 int number_of_literals = fun->NumberOfLiterals();
1754 Handle<FixedArray> literals =
1755 Factory::NewFixedArray(number_of_literals, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001756 if (number_of_literals > 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001757 // Insert the object, regexp and array functions in the literals
1758 // array prefix. These are the functions that will be used when
1759 // creating object, regexp and array literals.
ager@chromium.org236ad962008-09-25 09:45:57 +00001760 literals->set(JSFunction::kLiteralGlobalContextIndex,
1761 context->global_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001762 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001763 // It's okay to skip the write barrier here because the literals
1764 // are guaranteed to be in old space.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001765 target->set_literals(*literals, SKIP_WRITE_BARRIER);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001766 target->set_next_function_link(Heap::undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001767 }
1768
1769 target->set_context(*context);
1770 return *target;
1771}
1772
1773
lrn@chromium.org303ada72010-10-27 09:33:13 +00001774static MaybeObject* Runtime_SetExpectedNumberOfProperties(Arguments args) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001775 HandleScope scope;
1776 ASSERT(args.length() == 2);
1777 CONVERT_ARG_CHECKED(JSFunction, function, 0);
1778 CONVERT_SMI_CHECKED(num, args[1]);
1779 RUNTIME_ASSERT(num >= 0);
1780 SetExpectedNofProperties(function, num);
1781 return Heap::undefined_value();
1782}
1783
1784
lrn@chromium.org303ada72010-10-27 09:33:13 +00001785MUST_USE_RESULT static MaybeObject* CharFromCode(Object* char_code) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001786 uint32_t code;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001787 if (char_code->ToArrayIndex(&code)) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001788 if (code <= 0xffff) {
1789 return Heap::LookupSingleCharacterStringFromCode(code);
1790 }
1791 }
1792 return Heap::empty_string();
1793}
1794
1795
lrn@chromium.org303ada72010-10-27 09:33:13 +00001796static MaybeObject* Runtime_StringCharCodeAt(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001797 NoHandleAllocation ha;
1798 ASSERT(args.length() == 2);
1799
1800 CONVERT_CHECKED(String, subject, args[0]);
1801 Object* index = args[1];
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001802 RUNTIME_ASSERT(index->IsNumber());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001803
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001804 uint32_t i = 0;
1805 if (index->IsSmi()) {
1806 int value = Smi::cast(index)->value();
1807 if (value < 0) return Heap::nan_value();
1808 i = value;
1809 } else {
1810 ASSERT(index->IsHeapNumber());
1811 double value = HeapNumber::cast(index)->value();
1812 i = static_cast<uint32_t>(DoubleToInteger(value));
kasperl@chromium.org74e4e5e2010-01-25 10:15:52 +00001813 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001814
1815 // Flatten the string. If someone wants to get a char at an index
1816 // in a cons string, it is likely that more indices will be
1817 // accessed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001818 Object* flat;
1819 { MaybeObject* maybe_flat = subject->TryFlatten();
1820 if (!maybe_flat->ToObject(&flat)) return maybe_flat;
1821 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001822 subject = String::cast(flat);
1823
1824 if (i >= static_cast<uint32_t>(subject->length())) {
1825 return Heap::nan_value();
1826 }
1827
1828 return Smi::FromInt(subject->Get(i));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001829}
1830
1831
lrn@chromium.org303ada72010-10-27 09:33:13 +00001832static MaybeObject* Runtime_CharFromCode(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001833 NoHandleAllocation ha;
1834 ASSERT(args.length() == 1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001835 return CharFromCode(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001836}
1837
lrn@chromium.org25156de2010-04-06 13:10:27 +00001838
1839class FixedArrayBuilder {
1840 public:
1841 explicit FixedArrayBuilder(int initial_capacity)
1842 : array_(Factory::NewFixedArrayWithHoles(initial_capacity)),
1843 length_(0) {
1844 // Require a non-zero initial size. Ensures that doubling the size to
1845 // extend the array will work.
1846 ASSERT(initial_capacity > 0);
1847 }
1848
1849 explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
1850 : array_(backing_store),
1851 length_(0) {
1852 // Require a non-zero initial size. Ensures that doubling the size to
1853 // extend the array will work.
1854 ASSERT(backing_store->length() > 0);
1855 }
1856
1857 bool HasCapacity(int elements) {
1858 int length = array_->length();
1859 int required_length = length_ + elements;
1860 return (length >= required_length);
1861 }
1862
1863 void EnsureCapacity(int elements) {
1864 int length = array_->length();
1865 int required_length = length_ + elements;
1866 if (length < required_length) {
1867 int new_length = length;
1868 do {
1869 new_length *= 2;
1870 } while (new_length < required_length);
1871 Handle<FixedArray> extended_array =
1872 Factory::NewFixedArrayWithHoles(new_length);
1873 array_->CopyTo(0, *extended_array, 0, length_);
1874 array_ = extended_array;
1875 }
1876 }
1877
1878 void Add(Object* value) {
1879 ASSERT(length_ < capacity());
1880 array_->set(length_, value);
1881 length_++;
1882 }
1883
1884 void Add(Smi* value) {
1885 ASSERT(length_ < capacity());
1886 array_->set(length_, value);
1887 length_++;
1888 }
1889
1890 Handle<FixedArray> array() {
1891 return array_;
1892 }
1893
1894 int length() {
1895 return length_;
1896 }
1897
1898 int capacity() {
1899 return array_->length();
1900 }
1901
1902 Handle<JSArray> ToJSArray() {
1903 Handle<JSArray> result_array = Factory::NewJSArrayWithElements(array_);
1904 result_array->set_length(Smi::FromInt(length_));
1905 return result_array;
1906 }
1907
1908 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
1909 target_array->set_elements(*array_);
1910 target_array->set_length(Smi::FromInt(length_));
1911 return target_array;
1912 }
1913
1914 private:
1915 Handle<FixedArray> array_;
1916 int length_;
1917};
1918
1919
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001920// Forward declarations.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001921const int kStringBuilderConcatHelperLengthBits = 11;
1922const int kStringBuilderConcatHelperPositionBits = 19;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001923
1924template <typename schar>
1925static inline void StringBuilderConcatHelper(String*,
1926 schar*,
1927 FixedArray*,
1928 int);
1929
lrn@chromium.org25156de2010-04-06 13:10:27 +00001930typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
1931 StringBuilderSubstringLength;
1932typedef BitField<int,
1933 kStringBuilderConcatHelperLengthBits,
1934 kStringBuilderConcatHelperPositionBits>
1935 StringBuilderSubstringPosition;
1936
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001937
1938class ReplacementStringBuilder {
1939 public:
1940 ReplacementStringBuilder(Handle<String> subject, int estimated_part_count)
lrn@chromium.org25156de2010-04-06 13:10:27 +00001941 : array_builder_(estimated_part_count),
1942 subject_(subject),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001943 character_count_(0),
ager@chromium.org5ec48922009-05-05 07:25:34 +00001944 is_ascii_(subject->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001945 // Require a non-zero initial size. Ensures that doubling the size to
1946 // extend the array will work.
1947 ASSERT(estimated_part_count > 0);
1948 }
1949
lrn@chromium.org25156de2010-04-06 13:10:27 +00001950 static inline void AddSubjectSlice(FixedArrayBuilder* builder,
1951 int from,
1952 int to) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001953 ASSERT(from >= 0);
1954 int length = to - from;
1955 ASSERT(length > 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001956 if (StringBuilderSubstringLength::is_valid(length) &&
1957 StringBuilderSubstringPosition::is_valid(from)) {
1958 int encoded_slice = StringBuilderSubstringLength::encode(length) |
1959 StringBuilderSubstringPosition::encode(from);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001960 builder->Add(Smi::FromInt(encoded_slice));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001961 } else {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001962 // Otherwise encode as two smis.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001963 builder->Add(Smi::FromInt(-length));
1964 builder->Add(Smi::FromInt(from));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001965 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00001966 }
1967
1968
1969 void EnsureCapacity(int elements) {
1970 array_builder_.EnsureCapacity(elements);
1971 }
1972
1973
1974 void AddSubjectSlice(int from, int to) {
1975 AddSubjectSlice(&array_builder_, from, to);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001976 IncrementCharacterCount(to - from);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001977 }
1978
1979
1980 void AddString(Handle<String> string) {
1981 int length = string->length();
1982 ASSERT(length > 0);
1983 AddElement(*string);
ager@chromium.org5ec48922009-05-05 07:25:34 +00001984 if (!string->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001985 is_ascii_ = false;
1986 }
1987 IncrementCharacterCount(length);
1988 }
1989
1990
1991 Handle<String> ToString() {
lrn@chromium.org25156de2010-04-06 13:10:27 +00001992 if (array_builder_.length() == 0) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001993 return Factory::empty_string();
1994 }
1995
1996 Handle<String> joined_string;
1997 if (is_ascii_) {
1998 joined_string = NewRawAsciiString(character_count_);
1999 AssertNoAllocation no_alloc;
2000 SeqAsciiString* seq = SeqAsciiString::cast(*joined_string);
2001 char* char_buffer = seq->GetChars();
2002 StringBuilderConcatHelper(*subject_,
2003 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002004 *array_builder_.array(),
2005 array_builder_.length());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002006 } else {
2007 // Non-ASCII.
2008 joined_string = NewRawTwoByteString(character_count_);
2009 AssertNoAllocation no_alloc;
2010 SeqTwoByteString* seq = SeqTwoByteString::cast(*joined_string);
2011 uc16* char_buffer = seq->GetChars();
2012 StringBuilderConcatHelper(*subject_,
2013 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002014 *array_builder_.array(),
2015 array_builder_.length());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002016 }
2017 return joined_string;
2018 }
2019
2020
2021 void IncrementCharacterCount(int by) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002022 if (character_count_ > String::kMaxLength - by) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002023 V8::FatalProcessOutOfMemory("String.replace result too large.");
2024 }
2025 character_count_ += by;
2026 }
2027
lrn@chromium.org25156de2010-04-06 13:10:27 +00002028 Handle<JSArray> GetParts() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002029 return array_builder_.ToJSArray();
lrn@chromium.org25156de2010-04-06 13:10:27 +00002030 }
kmillikin@chromium.orgd9825192010-03-30 08:36:16 +00002031
lrn@chromium.org25156de2010-04-06 13:10:27 +00002032 private:
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002033 Handle<String> NewRawAsciiString(int size) {
2034 CALL_HEAP_FUNCTION(Heap::AllocateRawAsciiString(size), String);
2035 }
2036
2037
2038 Handle<String> NewRawTwoByteString(int size) {
2039 CALL_HEAP_FUNCTION(Heap::AllocateRawTwoByteString(size), String);
2040 }
2041
2042
2043 void AddElement(Object* element) {
2044 ASSERT(element->IsSmi() || element->IsString());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002045 ASSERT(array_builder_.capacity() > array_builder_.length());
2046 array_builder_.Add(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002047 }
2048
lrn@chromium.org25156de2010-04-06 13:10:27 +00002049 FixedArrayBuilder array_builder_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002050 Handle<String> subject_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002051 int character_count_;
2052 bool is_ascii_;
2053};
2054
2055
2056class CompiledReplacement {
2057 public:
2058 CompiledReplacement()
2059 : parts_(1), replacement_substrings_(0) {}
2060
2061 void Compile(Handle<String> replacement,
2062 int capture_count,
2063 int subject_length);
2064
2065 void Apply(ReplacementStringBuilder* builder,
2066 int match_from,
2067 int match_to,
2068 Handle<JSArray> last_match_info);
2069
2070 // Number of distinct parts of the replacement pattern.
2071 int parts() {
2072 return parts_.length();
2073 }
2074 private:
2075 enum PartType {
2076 SUBJECT_PREFIX = 1,
2077 SUBJECT_SUFFIX,
2078 SUBJECT_CAPTURE,
2079 REPLACEMENT_SUBSTRING,
2080 REPLACEMENT_STRING,
2081
2082 NUMBER_OF_PART_TYPES
2083 };
2084
2085 struct ReplacementPart {
2086 static inline ReplacementPart SubjectMatch() {
2087 return ReplacementPart(SUBJECT_CAPTURE, 0);
2088 }
2089 static inline ReplacementPart SubjectCapture(int capture_index) {
2090 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
2091 }
2092 static inline ReplacementPart SubjectPrefix() {
2093 return ReplacementPart(SUBJECT_PREFIX, 0);
2094 }
2095 static inline ReplacementPart SubjectSuffix(int subject_length) {
2096 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
2097 }
2098 static inline ReplacementPart ReplacementString() {
2099 return ReplacementPart(REPLACEMENT_STRING, 0);
2100 }
2101 static inline ReplacementPart ReplacementSubString(int from, int to) {
2102 ASSERT(from >= 0);
2103 ASSERT(to > from);
2104 return ReplacementPart(-from, to);
2105 }
2106
2107 // If tag <= 0 then it is the negation of a start index of a substring of
2108 // the replacement pattern, otherwise it's a value from PartType.
2109 ReplacementPart(int tag, int data)
2110 : tag(tag), data(data) {
2111 // Must be non-positive or a PartType value.
2112 ASSERT(tag < NUMBER_OF_PART_TYPES);
2113 }
2114 // Either a value of PartType or a non-positive number that is
2115 // the negation of an index into the replacement string.
2116 int tag;
2117 // The data value's interpretation depends on the value of tag:
2118 // tag == SUBJECT_PREFIX ||
2119 // tag == SUBJECT_SUFFIX: data is unused.
2120 // tag == SUBJECT_CAPTURE: data is the number of the capture.
2121 // tag == REPLACEMENT_SUBSTRING ||
2122 // tag == REPLACEMENT_STRING: data is index into array of substrings
2123 // of the replacement string.
2124 // tag <= 0: Temporary representation of the substring of the replacement
2125 // string ranging over -tag .. data.
2126 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
2127 // substring objects.
2128 int data;
2129 };
2130
2131 template<typename Char>
2132 static void ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
2133 Vector<Char> characters,
2134 int capture_count,
2135 int subject_length) {
2136 int length = characters.length();
2137 int last = 0;
2138 for (int i = 0; i < length; i++) {
2139 Char c = characters[i];
2140 if (c == '$') {
2141 int next_index = i + 1;
2142 if (next_index == length) { // No next character!
2143 break;
2144 }
2145 Char c2 = characters[next_index];
2146 switch (c2) {
2147 case '$':
2148 if (i > last) {
2149 // There is a substring before. Include the first "$".
2150 parts->Add(ReplacementPart::ReplacementSubString(last, next_index));
2151 last = next_index + 1; // Continue after the second "$".
2152 } else {
2153 // Let the next substring start with the second "$".
2154 last = next_index;
2155 }
2156 i = next_index;
2157 break;
2158 case '`':
2159 if (i > last) {
2160 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2161 }
2162 parts->Add(ReplacementPart::SubjectPrefix());
2163 i = next_index;
2164 last = i + 1;
2165 break;
2166 case '\'':
2167 if (i > last) {
2168 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2169 }
2170 parts->Add(ReplacementPart::SubjectSuffix(subject_length));
2171 i = next_index;
2172 last = i + 1;
2173 break;
2174 case '&':
2175 if (i > last) {
2176 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2177 }
2178 parts->Add(ReplacementPart::SubjectMatch());
2179 i = next_index;
2180 last = i + 1;
2181 break;
2182 case '0':
2183 case '1':
2184 case '2':
2185 case '3':
2186 case '4':
2187 case '5':
2188 case '6':
2189 case '7':
2190 case '8':
2191 case '9': {
2192 int capture_ref = c2 - '0';
2193 if (capture_ref > capture_count) {
2194 i = next_index;
2195 continue;
2196 }
2197 int second_digit_index = next_index + 1;
2198 if (second_digit_index < length) {
2199 // Peek ahead to see if we have two digits.
2200 Char c3 = characters[second_digit_index];
2201 if ('0' <= c3 && c3 <= '9') { // Double digits.
2202 int double_digit_ref = capture_ref * 10 + c3 - '0';
2203 if (double_digit_ref <= capture_count) {
2204 next_index = second_digit_index;
2205 capture_ref = double_digit_ref;
2206 }
2207 }
2208 }
2209 if (capture_ref > 0) {
2210 if (i > last) {
2211 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2212 }
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002213 ASSERT(capture_ref <= capture_count);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002214 parts->Add(ReplacementPart::SubjectCapture(capture_ref));
2215 last = next_index + 1;
2216 }
2217 i = next_index;
2218 break;
2219 }
2220 default:
2221 i = next_index;
2222 break;
2223 }
2224 }
2225 }
2226 if (length > last) {
2227 if (last == 0) {
2228 parts->Add(ReplacementPart::ReplacementString());
2229 } else {
2230 parts->Add(ReplacementPart::ReplacementSubString(last, length));
2231 }
2232 }
2233 }
2234
2235 ZoneList<ReplacementPart> parts_;
2236 ZoneList<Handle<String> > replacement_substrings_;
2237};
2238
2239
2240void CompiledReplacement::Compile(Handle<String> replacement,
2241 int capture_count,
2242 int subject_length) {
2243 ASSERT(replacement->IsFlat());
ager@chromium.org5ec48922009-05-05 07:25:34 +00002244 if (replacement->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002245 AssertNoAllocation no_alloc;
2246 ParseReplacementPattern(&parts_,
2247 replacement->ToAsciiVector(),
2248 capture_count,
2249 subject_length);
2250 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00002251 ASSERT(replacement->IsTwoByteRepresentation());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002252 AssertNoAllocation no_alloc;
2253
2254 ParseReplacementPattern(&parts_,
2255 replacement->ToUC16Vector(),
2256 capture_count,
2257 subject_length);
2258 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002259 // Find substrings of replacement string and create them as String objects.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002260 int substring_index = 0;
2261 for (int i = 0, n = parts_.length(); i < n; i++) {
2262 int tag = parts_[i].tag;
2263 if (tag <= 0) { // A replacement string slice.
2264 int from = -tag;
2265 int to = parts_[i].data;
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002266 replacement_substrings_.Add(Factory::NewSubString(replacement, from, to));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002267 parts_[i].tag = REPLACEMENT_SUBSTRING;
2268 parts_[i].data = substring_index;
2269 substring_index++;
2270 } else if (tag == REPLACEMENT_STRING) {
2271 replacement_substrings_.Add(replacement);
2272 parts_[i].data = substring_index;
2273 substring_index++;
2274 }
2275 }
2276}
2277
2278
2279void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
2280 int match_from,
2281 int match_to,
2282 Handle<JSArray> last_match_info) {
2283 for (int i = 0, n = parts_.length(); i < n; i++) {
2284 ReplacementPart part = parts_[i];
2285 switch (part.tag) {
2286 case SUBJECT_PREFIX:
2287 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
2288 break;
2289 case SUBJECT_SUFFIX: {
2290 int subject_length = part.data;
2291 if (match_to < subject_length) {
2292 builder->AddSubjectSlice(match_to, subject_length);
2293 }
2294 break;
2295 }
2296 case SUBJECT_CAPTURE: {
2297 int capture = part.data;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002298 FixedArray* match_info = FixedArray::cast(last_match_info->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002299 int from = RegExpImpl::GetCapture(match_info, capture * 2);
2300 int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1);
2301 if (from >= 0 && to > from) {
2302 builder->AddSubjectSlice(from, to);
2303 }
2304 break;
2305 }
2306 case REPLACEMENT_SUBSTRING:
2307 case REPLACEMENT_STRING:
2308 builder->AddString(replacement_substrings_[part.data]);
2309 break;
2310 default:
2311 UNREACHABLE();
2312 }
2313 }
2314}
2315
2316
2317
lrn@chromium.org303ada72010-10-27 09:33:13 +00002318MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
2319 String* subject,
2320 JSRegExp* regexp,
2321 String* replacement,
2322 JSArray* last_match_info) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002323 ASSERT(subject->IsFlat());
2324 ASSERT(replacement->IsFlat());
2325
2326 HandleScope handles;
2327
2328 int length = subject->length();
2329 Handle<String> subject_handle(subject);
2330 Handle<JSRegExp> regexp_handle(regexp);
2331 Handle<String> replacement_handle(replacement);
2332 Handle<JSArray> last_match_info_handle(last_match_info);
2333 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2334 subject_handle,
2335 0,
2336 last_match_info_handle);
2337 if (match.is_null()) {
2338 return Failure::Exception();
2339 }
2340 if (match->IsNull()) {
2341 return *subject_handle;
2342 }
2343
2344 int capture_count = regexp_handle->CaptureCount();
2345
2346 // CompiledReplacement uses zone allocation.
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00002347 CompilationZoneScope zone(DELETE_ON_EXIT);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002348 CompiledReplacement compiled_replacement;
2349 compiled_replacement.Compile(replacement_handle,
2350 capture_count,
2351 length);
2352
2353 bool is_global = regexp_handle->GetFlags().is_global();
2354
2355 // Guessing the number of parts that the final result string is built
2356 // from. Global regexps can match any number of times, so we guess
2357 // conservatively.
2358 int expected_parts =
2359 (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1;
2360 ReplacementStringBuilder builder(subject_handle, expected_parts);
2361
2362 // Index of end of last match.
2363 int prev = 0;
2364
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002365 // Number of parts added by compiled replacement plus preceeding
2366 // string and possibly suffix after last match. It is possible for
2367 // all components to use two elements when encoded as two smis.
2368 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002369 bool matched = true;
2370 do {
2371 ASSERT(last_match_info_handle->HasFastElements());
2372 // Increase the capacity of the builder before entering local handle-scope,
2373 // so its internal buffer can safely allocate a new handle if it grows.
2374 builder.EnsureCapacity(parts_added_per_loop);
2375
2376 HandleScope loop_scope;
2377 int start, end;
2378 {
2379 AssertNoAllocation match_info_array_is_not_in_a_handle;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002380 FixedArray* match_info_array =
2381 FixedArray::cast(last_match_info_handle->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002382
2383 ASSERT_EQ(capture_count * 2 + 2,
2384 RegExpImpl::GetLastCaptureCount(match_info_array));
2385 start = RegExpImpl::GetCapture(match_info_array, 0);
2386 end = RegExpImpl::GetCapture(match_info_array, 1);
2387 }
2388
2389 if (prev < start) {
2390 builder.AddSubjectSlice(prev, start);
2391 }
2392 compiled_replacement.Apply(&builder,
2393 start,
2394 end,
2395 last_match_info_handle);
2396 prev = end;
2397
2398 // Only continue checking for global regexps.
2399 if (!is_global) break;
2400
2401 // Continue from where the match ended, unless it was an empty match.
2402 int next = end;
2403 if (start == end) {
2404 next = end + 1;
2405 if (next > length) break;
2406 }
2407
2408 match = RegExpImpl::Exec(regexp_handle,
2409 subject_handle,
2410 next,
2411 last_match_info_handle);
2412 if (match.is_null()) {
2413 return Failure::Exception();
2414 }
2415 matched = !match->IsNull();
2416 } while (matched);
2417
2418 if (prev < length) {
2419 builder.AddSubjectSlice(prev, length);
2420 }
2421
2422 return *(builder.ToString());
2423}
2424
2425
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002426template <typename ResultSeqString>
lrn@chromium.org303ada72010-10-27 09:33:13 +00002427MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
2428 String* subject,
2429 JSRegExp* regexp,
2430 JSArray* last_match_info) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002431 ASSERT(subject->IsFlat());
2432
2433 HandleScope handles;
2434
2435 Handle<String> subject_handle(subject);
2436 Handle<JSRegExp> regexp_handle(regexp);
2437 Handle<JSArray> last_match_info_handle(last_match_info);
2438 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2439 subject_handle,
2440 0,
2441 last_match_info_handle);
2442 if (match.is_null()) return Failure::Exception();
2443 if (match->IsNull()) return *subject_handle;
2444
2445 ASSERT(last_match_info_handle->HasFastElements());
2446
2447 HandleScope loop_scope;
2448 int start, end;
2449 {
2450 AssertNoAllocation match_info_array_is_not_in_a_handle;
2451 FixedArray* match_info_array =
2452 FixedArray::cast(last_match_info_handle->elements());
2453
2454 start = RegExpImpl::GetCapture(match_info_array, 0);
2455 end = RegExpImpl::GetCapture(match_info_array, 1);
2456 }
2457
2458 int length = subject->length();
2459 int new_length = length - (end - start);
2460 if (new_length == 0) {
2461 return Heap::empty_string();
2462 }
2463 Handle<ResultSeqString> answer;
2464 if (ResultSeqString::kHasAsciiEncoding) {
2465 answer =
2466 Handle<ResultSeqString>::cast(Factory::NewRawAsciiString(new_length));
2467 } else {
2468 answer =
2469 Handle<ResultSeqString>::cast(Factory::NewRawTwoByteString(new_length));
2470 }
2471
2472 // If the regexp isn't global, only match once.
2473 if (!regexp_handle->GetFlags().is_global()) {
2474 if (start > 0) {
2475 String::WriteToFlat(*subject_handle,
2476 answer->GetChars(),
2477 0,
2478 start);
2479 }
2480 if (end < length) {
2481 String::WriteToFlat(*subject_handle,
2482 answer->GetChars() + start,
2483 end,
2484 length);
2485 }
2486 return *answer;
2487 }
2488
2489 int prev = 0; // Index of end of last match.
2490 int next = 0; // Start of next search (prev unless last match was empty).
2491 int position = 0;
2492
2493 do {
2494 if (prev < start) {
2495 // Add substring subject[prev;start] to answer string.
2496 String::WriteToFlat(*subject_handle,
2497 answer->GetChars() + position,
2498 prev,
2499 start);
2500 position += start - prev;
2501 }
2502 prev = end;
2503 next = end;
2504 // Continue from where the match ended, unless it was an empty match.
2505 if (start == end) {
2506 next++;
2507 if (next > length) break;
2508 }
2509 match = RegExpImpl::Exec(regexp_handle,
2510 subject_handle,
2511 next,
2512 last_match_info_handle);
2513 if (match.is_null()) return Failure::Exception();
2514 if (match->IsNull()) break;
2515
2516 ASSERT(last_match_info_handle->HasFastElements());
2517 HandleScope loop_scope;
2518 {
2519 AssertNoAllocation match_info_array_is_not_in_a_handle;
2520 FixedArray* match_info_array =
2521 FixedArray::cast(last_match_info_handle->elements());
2522 start = RegExpImpl::GetCapture(match_info_array, 0);
2523 end = RegExpImpl::GetCapture(match_info_array, 1);
2524 }
2525 } while (true);
2526
2527 if (prev < length) {
2528 // Add substring subject[prev;length] to answer string.
2529 String::WriteToFlat(*subject_handle,
2530 answer->GetChars() + position,
2531 prev,
2532 length);
2533 position += length - prev;
2534 }
2535
2536 if (position == 0) {
2537 return Heap::empty_string();
2538 }
2539
2540 // Shorten string and fill
2541 int string_size = ResultSeqString::SizeFor(position);
2542 int allocated_string_size = ResultSeqString::SizeFor(new_length);
2543 int delta = allocated_string_size - string_size;
2544
2545 answer->set_length(position);
2546 if (delta == 0) return *answer;
2547
2548 Address end_of_string = answer->address() + string_size;
2549 Heap::CreateFillerObjectAt(end_of_string, delta);
2550
2551 return *answer;
2552}
2553
2554
lrn@chromium.org303ada72010-10-27 09:33:13 +00002555static MaybeObject* Runtime_StringReplaceRegExpWithString(Arguments args) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002556 ASSERT(args.length() == 4);
2557
2558 CONVERT_CHECKED(String, subject, args[0]);
2559 if (!subject->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002560 Object* flat_subject;
2561 { MaybeObject* maybe_flat_subject = subject->TryFlatten();
2562 if (!maybe_flat_subject->ToObject(&flat_subject)) {
2563 return maybe_flat_subject;
2564 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002565 }
2566 subject = String::cast(flat_subject);
2567 }
2568
2569 CONVERT_CHECKED(String, replacement, args[2]);
2570 if (!replacement->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002571 Object* flat_replacement;
2572 { MaybeObject* maybe_flat_replacement = replacement->TryFlatten();
2573 if (!maybe_flat_replacement->ToObject(&flat_replacement)) {
2574 return maybe_flat_replacement;
2575 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002576 }
2577 replacement = String::cast(flat_replacement);
2578 }
2579
2580 CONVERT_CHECKED(JSRegExp, regexp, args[1]);
2581 CONVERT_CHECKED(JSArray, last_match_info, args[3]);
2582
2583 ASSERT(last_match_info->HasFastElements());
2584
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002585 if (replacement->length() == 0) {
2586 if (subject->HasOnlyAsciiChars()) {
2587 return StringReplaceRegExpWithEmptyString<SeqAsciiString>(
2588 subject, regexp, last_match_info);
2589 } else {
2590 return StringReplaceRegExpWithEmptyString<SeqTwoByteString>(
2591 subject, regexp, last_match_info);
2592 }
2593 }
2594
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002595 return StringReplaceRegExpWithString(subject,
2596 regexp,
2597 replacement,
2598 last_match_info);
2599}
2600
2601
ager@chromium.org7c537e22008-10-16 08:43:32 +00002602// Perform string match of pattern on subject, starting at start index.
2603// Caller must ensure that 0 <= start_index <= sub->length(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002604// and should check that pat->length() + start_index <= sub->length().
ager@chromium.org7c537e22008-10-16 08:43:32 +00002605int Runtime::StringMatch(Handle<String> sub,
2606 Handle<String> pat,
2607 int start_index) {
2608 ASSERT(0 <= start_index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002609 ASSERT(start_index <= sub->length());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002610
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00002611 int pattern_length = pat->length();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002612 if (pattern_length == 0) return start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002613
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002614 int subject_length = sub->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00002615 if (start_index + pattern_length > subject_length) return -1;
2616
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002617 if (!sub->IsFlat()) FlattenString(sub);
2618 if (!pat->IsFlat()) FlattenString(pat);
ager@chromium.org236ad962008-09-25 09:45:57 +00002619
ager@chromium.org7c537e22008-10-16 08:43:32 +00002620 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002621 // Extract flattened substrings of cons strings before determining asciiness.
2622 String* seq_sub = *sub;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002623 if (seq_sub->IsConsString()) seq_sub = ConsString::cast(seq_sub)->first();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002624 String* seq_pat = *pat;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002625 if (seq_pat->IsConsString()) seq_pat = ConsString::cast(seq_pat)->first();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002626
ager@chromium.org7c537e22008-10-16 08:43:32 +00002627 // dispatch on type of strings
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002628 if (seq_pat->IsAsciiRepresentation()) {
2629 Vector<const char> pat_vector = seq_pat->ToAsciiVector();
2630 if (seq_sub->IsAsciiRepresentation()) {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002631 return SearchString(seq_sub->ToAsciiVector(), pat_vector, start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00002632 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002633 return SearchString(seq_sub->ToUC16Vector(), pat_vector, start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00002634 }
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002635 Vector<const uc16> pat_vector = seq_pat->ToUC16Vector();
2636 if (seq_sub->IsAsciiRepresentation()) {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002637 return SearchString(seq_sub->ToAsciiVector(), pat_vector, start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002638 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002639 return SearchString(seq_sub->ToUC16Vector(), pat_vector, start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002640}
2641
2642
lrn@chromium.org303ada72010-10-27 09:33:13 +00002643static MaybeObject* Runtime_StringIndexOf(Arguments args) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00002644 HandleScope scope; // create a new handle scope
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002645 ASSERT(args.length() == 3);
2646
ager@chromium.org7c537e22008-10-16 08:43:32 +00002647 CONVERT_ARG_CHECKED(String, sub, 0);
2648 CONVERT_ARG_CHECKED(String, pat, 1);
2649
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002650 Object* index = args[2];
2651 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002652 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002653
ager@chromium.org870a0b62008-11-04 11:43:05 +00002654 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
ager@chromium.org7c537e22008-10-16 08:43:32 +00002655 int position = Runtime::StringMatch(sub, pat, start_index);
2656 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002657}
2658
2659
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002660template <typename schar, typename pchar>
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002661static int StringMatchBackwards(Vector<const schar> subject,
2662 Vector<const pchar> pattern,
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002663 int idx) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002664 int pattern_length = pattern.length();
2665 ASSERT(pattern_length >= 1);
2666 ASSERT(idx + pattern_length <= subject.length());
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002667
2668 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002669 for (int i = 0; i < pattern_length; i++) {
2670 uc16 c = pattern[i];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002671 if (c > String::kMaxAsciiCharCode) {
2672 return -1;
2673 }
2674 }
2675 }
2676
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002677 pchar pattern_first_char = pattern[0];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002678 for (int i = idx; i >= 0; i--) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002679 if (subject[i] != pattern_first_char) continue;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002680 int j = 1;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002681 while (j < pattern_length) {
2682 if (pattern[j] != subject[i+j]) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002683 break;
2684 }
2685 j++;
2686 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002687 if (j == pattern_length) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002688 return i;
2689 }
2690 }
2691 return -1;
2692}
2693
lrn@chromium.org303ada72010-10-27 09:33:13 +00002694static MaybeObject* Runtime_StringLastIndexOf(Arguments args) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002695 HandleScope scope; // create a new handle scope
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002696 ASSERT(args.length() == 3);
2697
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002698 CONVERT_ARG_CHECKED(String, sub, 0);
2699 CONVERT_ARG_CHECKED(String, pat, 1);
2700
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002701 Object* index = args[2];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002702 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002703 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002704
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002705 uint32_t pat_length = pat->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002706 uint32_t sub_length = sub->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002707
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002708 if (start_index + pat_length > sub_length) {
2709 start_index = sub_length - pat_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +00002710 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002711
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002712 if (pat_length == 0) {
2713 return Smi::FromInt(start_index);
2714 }
2715
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002716 if (!sub->IsFlat()) FlattenString(sub);
2717 if (!pat->IsFlat()) FlattenString(pat);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002718
2719 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
2720
2721 int position = -1;
2722
2723 if (pat->IsAsciiRepresentation()) {
2724 Vector<const char> pat_vector = pat->ToAsciiVector();
2725 if (sub->IsAsciiRepresentation()) {
2726 position = StringMatchBackwards(sub->ToAsciiVector(),
2727 pat_vector,
2728 start_index);
2729 } else {
2730 position = StringMatchBackwards(sub->ToUC16Vector(),
2731 pat_vector,
2732 start_index);
2733 }
2734 } else {
2735 Vector<const uc16> pat_vector = pat->ToUC16Vector();
2736 if (sub->IsAsciiRepresentation()) {
2737 position = StringMatchBackwards(sub->ToAsciiVector(),
2738 pat_vector,
2739 start_index);
2740 } else {
2741 position = StringMatchBackwards(sub->ToUC16Vector(),
2742 pat_vector,
2743 start_index);
2744 }
2745 }
2746
2747 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002748}
2749
2750
lrn@chromium.org303ada72010-10-27 09:33:13 +00002751static MaybeObject* Runtime_StringLocaleCompare(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002752 NoHandleAllocation ha;
2753 ASSERT(args.length() == 2);
2754
2755 CONVERT_CHECKED(String, str1, args[0]);
2756 CONVERT_CHECKED(String, str2, args[1]);
2757
2758 if (str1 == str2) return Smi::FromInt(0); // Equal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002759 int str1_length = str1->length();
2760 int str2_length = str2->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002761
2762 // Decide trivial cases without flattening.
2763 if (str1_length == 0) {
2764 if (str2_length == 0) return Smi::FromInt(0); // Equal.
2765 return Smi::FromInt(-str2_length);
2766 } else {
2767 if (str2_length == 0) return Smi::FromInt(str1_length);
2768 }
2769
2770 int end = str1_length < str2_length ? str1_length : str2_length;
2771
2772 // No need to flatten if we are going to find the answer on the first
2773 // character. At this point we know there is at least one character
2774 // in each string, due to the trivial case handling above.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002775 int d = str1->Get(0) - str2->Get(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002776 if (d != 0) return Smi::FromInt(d);
2777
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002778 str1->TryFlatten();
2779 str2->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002780
2781 static StringInputBuffer buf1;
2782 static StringInputBuffer buf2;
2783
2784 buf1.Reset(str1);
2785 buf2.Reset(str2);
2786
2787 for (int i = 0; i < end; i++) {
2788 uint16_t char1 = buf1.GetNext();
2789 uint16_t char2 = buf2.GetNext();
2790 if (char1 != char2) return Smi::FromInt(char1 - char2);
2791 }
2792
2793 return Smi::FromInt(str1_length - str2_length);
2794}
2795
2796
lrn@chromium.org303ada72010-10-27 09:33:13 +00002797static MaybeObject* Runtime_SubString(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002798 NoHandleAllocation ha;
2799 ASSERT(args.length() == 3);
2800
2801 CONVERT_CHECKED(String, value, args[0]);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002802 Object* from = args[1];
2803 Object* to = args[2];
2804 int start, end;
2805 // We have a fast integer-only case here to avoid a conversion to double in
2806 // the common case where from and to are Smis.
2807 if (from->IsSmi() && to->IsSmi()) {
2808 start = Smi::cast(from)->value();
2809 end = Smi::cast(to)->value();
2810 } else {
2811 CONVERT_DOUBLE_CHECKED(from_number, from);
2812 CONVERT_DOUBLE_CHECKED(to_number, to);
2813 start = FastD2I(from_number);
2814 end = FastD2I(to_number);
2815 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002816 RUNTIME_ASSERT(end >= start);
2817 RUNTIME_ASSERT(start >= 0);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00002818 RUNTIME_ASSERT(end <= value->length());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002819 Counters::sub_string_runtime.Increment();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002820 return value->SubString(start, end);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002821}
2822
2823
lrn@chromium.org303ada72010-10-27 09:33:13 +00002824static MaybeObject* Runtime_StringMatch(Arguments args) {
ager@chromium.org41826e72009-03-30 13:30:57 +00002825 ASSERT_EQ(3, args.length());
2826
2827 CONVERT_ARG_CHECKED(String, subject, 0);
2828 CONVERT_ARG_CHECKED(JSRegExp, regexp, 1);
2829 CONVERT_ARG_CHECKED(JSArray, regexp_info, 2);
2830 HandleScope handles;
2831
2832 Handle<Object> match = RegExpImpl::Exec(regexp, subject, 0, regexp_info);
2833
2834 if (match.is_null()) {
2835 return Failure::Exception();
2836 }
2837 if (match->IsNull()) {
2838 return Heap::null_value();
2839 }
2840 int length = subject->length();
2841
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00002842 CompilationZoneScope zone_space(DELETE_ON_EXIT);
ager@chromium.org41826e72009-03-30 13:30:57 +00002843 ZoneList<int> offsets(8);
2844 do {
2845 int start;
2846 int end;
2847 {
2848 AssertNoAllocation no_alloc;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002849 FixedArray* elements = FixedArray::cast(regexp_info->elements());
ager@chromium.org41826e72009-03-30 13:30:57 +00002850 start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value();
2851 end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value();
2852 }
2853 offsets.Add(start);
2854 offsets.Add(end);
2855 int index = start < end ? end : end + 1;
2856 if (index > length) break;
2857 match = RegExpImpl::Exec(regexp, subject, index, regexp_info);
2858 if (match.is_null()) {
2859 return Failure::Exception();
2860 }
2861 } while (!match->IsNull());
2862 int matches = offsets.length() / 2;
2863 Handle<FixedArray> elements = Factory::NewFixedArray(matches);
2864 for (int i = 0; i < matches ; i++) {
2865 int from = offsets.at(i * 2);
2866 int to = offsets.at(i * 2 + 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002867 Handle<String> match = Factory::NewSubString(subject, from, to);
2868 elements->set(i, *match);
ager@chromium.org41826e72009-03-30 13:30:57 +00002869 }
2870 Handle<JSArray> result = Factory::NewJSArrayWithElements(elements);
2871 result->set_length(Smi::FromInt(matches));
2872 return *result;
2873}
2874
2875
lrn@chromium.org25156de2010-04-06 13:10:27 +00002876// Two smis before and after the match, for very long strings.
2877const int kMaxBuilderEntriesPerRegExpMatch = 5;
2878
2879
2880static void SetLastMatchInfoNoCaptures(Handle<String> subject,
2881 Handle<JSArray> last_match_info,
2882 int match_start,
2883 int match_end) {
2884 // Fill last_match_info with a single capture.
2885 last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead);
2886 AssertNoAllocation no_gc;
2887 FixedArray* elements = FixedArray::cast(last_match_info->elements());
2888 RegExpImpl::SetLastCaptureCount(elements, 2);
2889 RegExpImpl::SetLastInput(elements, *subject);
2890 RegExpImpl::SetLastSubject(elements, *subject);
2891 RegExpImpl::SetCapture(elements, 0, match_start);
2892 RegExpImpl::SetCapture(elements, 1, match_end);
2893}
2894
2895
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002896template <typename SubjectChar, typename PatternChar>
2897static bool SearchStringMultiple(Vector<const SubjectChar> subject,
2898 Vector<const PatternChar> pattern,
2899 String* pattern_string,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002900 FixedArrayBuilder* builder,
2901 int* match_pos) {
2902 int pos = *match_pos;
2903 int subject_length = subject.length();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002904 int pattern_length = pattern.length();
lrn@chromium.org25156de2010-04-06 13:10:27 +00002905 int max_search_start = subject_length - pattern_length;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002906 StringSearch<PatternChar, SubjectChar> search(pattern);
2907 while (pos <= max_search_start) {
2908 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
2909 *match_pos = pos;
2910 return false;
2911 }
2912 // Position of end of previous match.
2913 int match_end = pos + pattern_length;
2914 int new_pos = search.Search(subject, match_end);
2915 if (new_pos >= 0) {
2916 // A match.
2917 if (new_pos > match_end) {
2918 ReplacementStringBuilder::AddSubjectSlice(builder,
2919 match_end,
2920 new_pos);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002921 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002922 pos = new_pos;
2923 builder->Add(pattern_string);
2924 } else {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002925 break;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002926 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00002927 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002928
lrn@chromium.org25156de2010-04-06 13:10:27 +00002929 if (pos < max_search_start) {
2930 ReplacementStringBuilder::AddSubjectSlice(builder,
2931 pos + pattern_length,
2932 subject_length);
2933 }
2934 *match_pos = pos;
2935 return true;
2936}
2937
2938
2939static bool SearchStringMultiple(Handle<String> subject,
2940 Handle<String> pattern,
2941 Handle<JSArray> last_match_info,
2942 FixedArrayBuilder* builder) {
2943 ASSERT(subject->IsFlat());
2944 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002945
2946 // Treating as if a previous match was before first character.
2947 int match_pos = -pattern->length();
2948
2949 for (;;) { // Break when search complete.
2950 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
2951 AssertNoAllocation no_gc;
2952 if (subject->IsAsciiRepresentation()) {
2953 Vector<const char> subject_vector = subject->ToAsciiVector();
2954 if (pattern->IsAsciiRepresentation()) {
2955 if (SearchStringMultiple(subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002956 pattern->ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002957 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002958 builder,
2959 &match_pos)) break;
2960 } else {
2961 if (SearchStringMultiple(subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002962 pattern->ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002963 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002964 builder,
2965 &match_pos)) break;
2966 }
2967 } else {
2968 Vector<const uc16> subject_vector = subject->ToUC16Vector();
2969 if (pattern->IsAsciiRepresentation()) {
2970 if (SearchStringMultiple(subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002971 pattern->ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002972 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002973 builder,
2974 &match_pos)) break;
2975 } else {
2976 if (SearchStringMultiple(subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002977 pattern->ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002978 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002979 builder,
2980 &match_pos)) break;
2981 }
2982 }
2983 }
2984
2985 if (match_pos >= 0) {
2986 SetLastMatchInfoNoCaptures(subject,
2987 last_match_info,
2988 match_pos,
2989 match_pos + pattern->length());
2990 return true;
2991 }
2992 return false; // No matches at all.
2993}
2994
2995
2996static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple(
2997 Handle<String> subject,
2998 Handle<JSRegExp> regexp,
2999 Handle<JSArray> last_match_array,
3000 FixedArrayBuilder* builder) {
3001 ASSERT(subject->IsFlat());
3002 int match_start = -1;
3003 int match_end = 0;
3004 int pos = 0;
3005 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3006 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3007
3008 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003009 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003010 int subject_length = subject->length();
3011
3012 for (;;) { // Break on failure, return on exception.
3013 RegExpImpl::IrregexpResult result =
3014 RegExpImpl::IrregexpExecOnce(regexp,
3015 subject,
3016 pos,
3017 register_vector);
3018 if (result == RegExpImpl::RE_SUCCESS) {
3019 match_start = register_vector[0];
3020 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3021 if (match_end < match_start) {
3022 ReplacementStringBuilder::AddSubjectSlice(builder,
3023 match_end,
3024 match_start);
3025 }
3026 match_end = register_vector[1];
3027 HandleScope loop_scope;
3028 builder->Add(*Factory::NewSubString(subject, match_start, match_end));
3029 if (match_start != match_end) {
3030 pos = match_end;
3031 } else {
3032 pos = match_end + 1;
3033 if (pos > subject_length) break;
3034 }
3035 } else if (result == RegExpImpl::RE_FAILURE) {
3036 break;
3037 } else {
3038 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3039 return result;
3040 }
3041 }
3042
3043 if (match_start >= 0) {
3044 if (match_end < subject_length) {
3045 ReplacementStringBuilder::AddSubjectSlice(builder,
3046 match_end,
3047 subject_length);
3048 }
3049 SetLastMatchInfoNoCaptures(subject,
3050 last_match_array,
3051 match_start,
3052 match_end);
3053 return RegExpImpl::RE_SUCCESS;
3054 } else {
3055 return RegExpImpl::RE_FAILURE; // No matches at all.
3056 }
3057}
3058
3059
3060static RegExpImpl::IrregexpResult SearchRegExpMultiple(
3061 Handle<String> subject,
3062 Handle<JSRegExp> regexp,
3063 Handle<JSArray> last_match_array,
3064 FixedArrayBuilder* builder) {
3065
3066 ASSERT(subject->IsFlat());
3067 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3068 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3069
3070 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003071 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003072
3073 RegExpImpl::IrregexpResult result =
3074 RegExpImpl::IrregexpExecOnce(regexp,
3075 subject,
3076 0,
3077 register_vector);
3078
3079 int capture_count = regexp->CaptureCount();
3080 int subject_length = subject->length();
3081
3082 // Position to search from.
3083 int pos = 0;
3084 // End of previous match. Differs from pos if match was empty.
3085 int match_end = 0;
3086 if (result == RegExpImpl::RE_SUCCESS) {
3087 // Need to keep a copy of the previous match for creating last_match_info
3088 // at the end, so we have two vectors that we swap between.
3089 OffsetsVector registers2(required_registers);
3090 Vector<int> prev_register_vector(registers2.vector(), registers2.length());
3091
3092 do {
3093 int match_start = register_vector[0];
3094 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3095 if (match_end < match_start) {
3096 ReplacementStringBuilder::AddSubjectSlice(builder,
3097 match_end,
3098 match_start);
3099 }
3100 match_end = register_vector[1];
3101
3102 {
3103 // Avoid accumulating new handles inside loop.
3104 HandleScope temp_scope;
3105 // Arguments array to replace function is match, captures, index and
3106 // subject, i.e., 3 + capture count in total.
3107 Handle<FixedArray> elements = Factory::NewFixedArray(3 + capture_count);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003108 Handle<String> match = Factory::NewSubString(subject,
3109 match_start,
3110 match_end);
3111 elements->set(0, *match);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003112 for (int i = 1; i <= capture_count; i++) {
3113 int start = register_vector[i * 2];
3114 if (start >= 0) {
3115 int end = register_vector[i * 2 + 1];
3116 ASSERT(start <= end);
3117 Handle<String> substring = Factory::NewSubString(subject,
3118 start,
3119 end);
3120 elements->set(i, *substring);
3121 } else {
3122 ASSERT(register_vector[i * 2 + 1] < 0);
3123 elements->set(i, Heap::undefined_value());
3124 }
3125 }
3126 elements->set(capture_count + 1, Smi::FromInt(match_start));
3127 elements->set(capture_count + 2, *subject);
3128 builder->Add(*Factory::NewJSArrayWithElements(elements));
3129 }
3130 // Swap register vectors, so the last successful match is in
3131 // prev_register_vector.
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003132 Vector<int32_t> tmp = prev_register_vector;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003133 prev_register_vector = register_vector;
3134 register_vector = tmp;
3135
3136 if (match_end > match_start) {
3137 pos = match_end;
3138 } else {
3139 pos = match_end + 1;
3140 if (pos > subject_length) {
3141 break;
3142 }
3143 }
3144
3145 result = RegExpImpl::IrregexpExecOnce(regexp,
3146 subject,
3147 pos,
3148 register_vector);
3149 } while (result == RegExpImpl::RE_SUCCESS);
3150
3151 if (result != RegExpImpl::RE_EXCEPTION) {
3152 // Finished matching, with at least one match.
3153 if (match_end < subject_length) {
3154 ReplacementStringBuilder::AddSubjectSlice(builder,
3155 match_end,
3156 subject_length);
3157 }
3158
3159 int last_match_capture_count = (capture_count + 1) * 2;
3160 int last_match_array_size =
3161 last_match_capture_count + RegExpImpl::kLastMatchOverhead;
3162 last_match_array->EnsureSize(last_match_array_size);
3163 AssertNoAllocation no_gc;
3164 FixedArray* elements = FixedArray::cast(last_match_array->elements());
3165 RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count);
3166 RegExpImpl::SetLastSubject(elements, *subject);
3167 RegExpImpl::SetLastInput(elements, *subject);
3168 for (int i = 0; i < last_match_capture_count; i++) {
3169 RegExpImpl::SetCapture(elements, i, prev_register_vector[i]);
3170 }
3171 return RegExpImpl::RE_SUCCESS;
3172 }
3173 }
3174 // No matches at all, return failure or exception result directly.
3175 return result;
3176}
3177
3178
lrn@chromium.org303ada72010-10-27 09:33:13 +00003179static MaybeObject* Runtime_RegExpExecMultiple(Arguments args) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003180 ASSERT(args.length() == 4);
3181 HandleScope handles;
3182
3183 CONVERT_ARG_CHECKED(String, subject, 1);
3184 if (!subject->IsFlat()) { FlattenString(subject); }
3185 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
3186 CONVERT_ARG_CHECKED(JSArray, last_match_info, 2);
3187 CONVERT_ARG_CHECKED(JSArray, result_array, 3);
3188
3189 ASSERT(last_match_info->HasFastElements());
3190 ASSERT(regexp->GetFlags().is_global());
3191 Handle<FixedArray> result_elements;
3192 if (result_array->HasFastElements()) {
3193 result_elements =
3194 Handle<FixedArray>(FixedArray::cast(result_array->elements()));
3195 } else {
3196 result_elements = Factory::NewFixedArrayWithHoles(16);
3197 }
3198 FixedArrayBuilder builder(result_elements);
3199
3200 if (regexp->TypeTag() == JSRegExp::ATOM) {
3201 Handle<String> pattern(
3202 String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003203 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003204 if (SearchStringMultiple(subject, pattern, last_match_info, &builder)) {
3205 return *builder.ToJSArray(result_array);
3206 }
3207 return Heap::null_value();
3208 }
3209
3210 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
3211
3212 RegExpImpl::IrregexpResult result;
3213 if (regexp->CaptureCount() == 0) {
3214 result = SearchRegExpNoCaptureMultiple(subject,
3215 regexp,
3216 last_match_info,
3217 &builder);
3218 } else {
3219 result = SearchRegExpMultiple(subject, regexp, last_match_info, &builder);
3220 }
3221 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array);
3222 if (result == RegExpImpl::RE_FAILURE) return Heap::null_value();
3223 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3224 return Failure::Exception();
3225}
3226
3227
lrn@chromium.org303ada72010-10-27 09:33:13 +00003228static MaybeObject* Runtime_NumberToRadixString(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003229 NoHandleAllocation ha;
3230 ASSERT(args.length() == 2);
3231
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003232 // Fast case where the result is a one character string.
3233 if (args[0]->IsSmi() && args[1]->IsSmi()) {
3234 int value = Smi::cast(args[0])->value();
3235 int radix = Smi::cast(args[1])->value();
3236 if (value >= 0 && value < radix) {
3237 RUNTIME_ASSERT(radix <= 36);
3238 // Character array used for conversion.
3239 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
3240 return Heap::LookupSingleCharacterStringFromCode(kCharTable[value]);
3241 }
3242 }
3243
3244 // Slow case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003245 CONVERT_DOUBLE_CHECKED(value, args[0]);
3246 if (isnan(value)) {
3247 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
3248 }
3249 if (isinf(value)) {
3250 if (value < 0) {
3251 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
3252 }
3253 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
3254 }
3255 CONVERT_DOUBLE_CHECKED(radix_number, args[1]);
3256 int radix = FastD2I(radix_number);
3257 RUNTIME_ASSERT(2 <= radix && radix <= 36);
3258 char* str = DoubleToRadixCString(value, radix);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003259 MaybeObject* result = Heap::AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003260 DeleteArray(str);
3261 return result;
3262}
3263
3264
lrn@chromium.org303ada72010-10-27 09:33:13 +00003265static MaybeObject* Runtime_NumberToFixed(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003266 NoHandleAllocation ha;
3267 ASSERT(args.length() == 2);
3268
3269 CONVERT_DOUBLE_CHECKED(value, args[0]);
3270 if (isnan(value)) {
3271 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
3272 }
3273 if (isinf(value)) {
3274 if (value < 0) {
3275 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
3276 }
3277 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
3278 }
3279 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3280 int f = FastD2I(f_number);
3281 RUNTIME_ASSERT(f >= 0);
3282 char* str = DoubleToFixedCString(value, f);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003283 MaybeObject* result = Heap::AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003284 DeleteArray(str);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003285 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003286}
3287
3288
lrn@chromium.org303ada72010-10-27 09:33:13 +00003289static MaybeObject* Runtime_NumberToExponential(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003290 NoHandleAllocation ha;
3291 ASSERT(args.length() == 2);
3292
3293 CONVERT_DOUBLE_CHECKED(value, args[0]);
3294 if (isnan(value)) {
3295 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
3296 }
3297 if (isinf(value)) {
3298 if (value < 0) {
3299 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
3300 }
3301 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
3302 }
3303 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3304 int f = FastD2I(f_number);
3305 RUNTIME_ASSERT(f >= -1 && f <= 20);
3306 char* str = DoubleToExponentialCString(value, f);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003307 MaybeObject* result = Heap::AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003308 DeleteArray(str);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003309 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003310}
3311
3312
lrn@chromium.org303ada72010-10-27 09:33:13 +00003313static MaybeObject* Runtime_NumberToPrecision(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003314 NoHandleAllocation ha;
3315 ASSERT(args.length() == 2);
3316
3317 CONVERT_DOUBLE_CHECKED(value, args[0]);
3318 if (isnan(value)) {
3319 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
3320 }
3321 if (isinf(value)) {
3322 if (value < 0) {
3323 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
3324 }
3325 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
3326 }
3327 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3328 int f = FastD2I(f_number);
3329 RUNTIME_ASSERT(f >= 1 && f <= 21);
3330 char* str = DoubleToPrecisionCString(value, f);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003331 MaybeObject* result = Heap::AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003332 DeleteArray(str);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003333 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003334}
3335
3336
3337// Returns a single character string where first character equals
3338// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003339static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003340 if (index < static_cast<uint32_t>(string->length())) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003341 string->TryFlatten();
ager@chromium.org870a0b62008-11-04 11:43:05 +00003342 return LookupSingleCharacterStringFromCode(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003343 string->Get(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003344 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003345 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003346}
3347
3348
lrn@chromium.org303ada72010-10-27 09:33:13 +00003349MaybeObject* Runtime::GetElementOrCharAt(Handle<Object> object,
3350 uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003351 // Handle [] indexing on Strings
3352 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003353 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
3354 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003355 }
3356
3357 // Handle [] indexing on String objects
3358 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003359 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
3360 Handle<Object> result =
3361 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
3362 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003363 }
3364
3365 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003366 Handle<Object> prototype = GetPrototype(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003367 return prototype->GetElement(index);
3368 }
3369
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003370 return GetElement(object, index);
3371}
3372
3373
lrn@chromium.org303ada72010-10-27 09:33:13 +00003374MaybeObject* Runtime::GetElement(Handle<Object> object, uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003375 return object->GetElement(index);
3376}
3377
3378
lrn@chromium.org303ada72010-10-27 09:33:13 +00003379MaybeObject* Runtime::GetObjectProperty(Handle<Object> object,
3380 Handle<Object> key) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003381 HandleScope scope;
3382
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003383 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003384 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003385 Handle<Object> error =
3386 Factory::NewTypeError("non_object_property_load",
3387 HandleVector(args, 2));
3388 return Top::Throw(*error);
3389 }
3390
3391 // Check if the given key is an array index.
3392 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003393 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003394 return GetElementOrCharAt(object, index);
3395 }
3396
3397 // Convert the key to a string - possibly by calling back into JavaScript.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003398 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003399 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003400 name = Handle<String>::cast(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003401 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003402 bool has_pending_exception = false;
3403 Handle<Object> converted =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003404 Execution::ToString(key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003405 if (has_pending_exception) return Failure::Exception();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003406 name = Handle<String>::cast(converted);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003407 }
3408
ager@chromium.org32912102009-01-16 10:38:43 +00003409 // Check if the name is trivially convertible to an index and get
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003410 // the element if so.
3411 if (name->AsArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003412 return GetElementOrCharAt(object, index);
3413 } else {
3414 PropertyAttributes attr;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003415 return object->GetProperty(*name, &attr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003416 }
3417}
3418
3419
lrn@chromium.org303ada72010-10-27 09:33:13 +00003420static MaybeObject* Runtime_GetProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003421 NoHandleAllocation ha;
3422 ASSERT(args.length() == 2);
3423
3424 Handle<Object> object = args.at<Object>(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003425 Handle<Object> key = args.at<Object>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003426
3427 return Runtime::GetObjectProperty(object, key);
3428}
3429
3430
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003431// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003432static MaybeObject* Runtime_KeyedGetProperty(Arguments args) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00003433 NoHandleAllocation ha;
3434 ASSERT(args.length() == 2);
3435
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003436 // Fast cases for getting named properties of the receiver JSObject
ager@chromium.org8bb60582008-12-11 12:02:20 +00003437 // itself.
3438 //
3439 // The global proxy objects has to be excluded since LocalLookup on
ager@chromium.org32912102009-01-16 10:38:43 +00003440 // the global proxy object can return a valid result even though the
ager@chromium.org8bb60582008-12-11 12:02:20 +00003441 // global proxy object never has properties. This is the case
3442 // because the global proxy object forwards everything to its hidden
3443 // prototype including local lookups.
3444 //
3445 // Additionally, we need to make sure that we do not cache results
3446 // for objects that require access checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003447 if (args[0]->IsJSObject() &&
3448 !args[0]->IsJSGlobalProxy() &&
ager@chromium.org8bb60582008-12-11 12:02:20 +00003449 !args[0]->IsAccessCheckNeeded() &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003450 args[1]->IsString()) {
3451 JSObject* receiver = JSObject::cast(args[0]);
3452 String* key = String::cast(args[1]);
3453 if (receiver->HasFastProperties()) {
3454 // Attempt to use lookup cache.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003455 Map* receiver_map = receiver->map();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00003456 int offset = KeyedLookupCache::Lookup(receiver_map, key);
3457 if (offset != -1) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003458 Object* value = receiver->FastPropertyAt(offset);
3459 return value->IsTheHole() ? Heap::undefined_value() : value;
3460 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003461 // Lookup cache miss. Perform lookup and update the cache if appropriate.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003462 LookupResult result;
3463 receiver->LocalLookup(key, &result);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00003464 if (result.IsProperty() && result.type() == FIELD) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003465 int offset = result.GetFieldIndex();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00003466 KeyedLookupCache::Update(receiver_map, key, offset);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003467 return receiver->FastPropertyAt(offset);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003468 }
3469 } else {
3470 // Attempt dictionary lookup.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00003471 StringDictionary* dictionary = receiver->property_dictionary();
3472 int entry = dictionary->FindEntry(key);
3473 if ((entry != StringDictionary::kNotFound) &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003474 (dictionary->DetailsAt(entry).type() == NORMAL)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003475 Object* value = dictionary->ValueAt(entry);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003476 if (!receiver->IsGlobalObject()) return value;
3477 value = JSGlobalPropertyCell::cast(value)->value();
3478 if (!value->IsTheHole()) return value;
3479 // If value is the hole do the general lookup.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003480 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00003481 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003482 } else if (args[0]->IsString() && args[1]->IsSmi()) {
3483 // Fast case for string indexing using [] with a smi index.
3484 HandleScope scope;
3485 Handle<String> str = args.at<String>(0);
3486 int index = Smi::cast(args[1])->value();
3487 Handle<Object> result = GetCharAt(str, index);
3488 return *result;
ager@chromium.org7c537e22008-10-16 08:43:32 +00003489 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003490
3491 // Fall back to GetObjectProperty.
ager@chromium.org7c537e22008-10-16 08:43:32 +00003492 return Runtime::GetObjectProperty(args.at<Object>(0),
3493 args.at<Object>(1));
3494}
3495
3496
lrn@chromium.org303ada72010-10-27 09:33:13 +00003497static MaybeObject* Runtime_DefineOrRedefineAccessorProperty(Arguments args) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003498 ASSERT(args.length() == 5);
3499 HandleScope scope;
3500 CONVERT_ARG_CHECKED(JSObject, obj, 0);
3501 CONVERT_CHECKED(String, name, args[1]);
3502 CONVERT_CHECKED(Smi, flag_setter, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003503 Object* fun = args[3];
3504 RUNTIME_ASSERT(fun->IsJSFunction() || fun->IsUndefined());
ager@chromium.org5c838252010-02-19 08:53:10 +00003505 CONVERT_CHECKED(Smi, flag_attr, args[4]);
3506 int unchecked = flag_attr->value();
3507 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3508 RUNTIME_ASSERT(!obj->IsNull());
3509 LookupResult result;
3510 obj->LocalLookupRealNamedProperty(name, &result);
3511
3512 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
3513 // If an existing property is either FIELD, NORMAL or CONSTANT_FUNCTION
3514 // delete it to avoid running into trouble in DefineAccessor, which
3515 // handles this incorrectly if the property is readonly (does nothing)
3516 if (result.IsProperty() &&
3517 (result.type() == FIELD || result.type() == NORMAL
3518 || result.type() == CONSTANT_FUNCTION)) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003519 Object* ok;
3520 { MaybeObject* maybe_ok =
3521 obj->DeleteProperty(name, JSObject::NORMAL_DELETION);
3522 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
3523 }
ager@chromium.org5c838252010-02-19 08:53:10 +00003524 }
3525 return obj->DefineAccessor(name, flag_setter->value() == 0, fun, attr);
3526}
3527
lrn@chromium.org303ada72010-10-27 09:33:13 +00003528static MaybeObject* Runtime_DefineOrRedefineDataProperty(Arguments args) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003529 ASSERT(args.length() == 4);
3530 HandleScope scope;
3531 CONVERT_ARG_CHECKED(JSObject, js_object, 0);
3532 CONVERT_ARG_CHECKED(String, name, 1);
3533 Handle<Object> obj_value = args.at<Object>(2);
3534
3535 CONVERT_CHECKED(Smi, flag, args[3]);
3536 int unchecked = flag->value();
3537 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3538
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003539 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
3540
3541 // Check if this is an element.
3542 uint32_t index;
3543 bool is_element = name->AsArrayIndex(&index);
3544
3545 // Special case for elements if any of the flags are true.
3546 // If elements are in fast case we always implicitly assume that:
3547 // DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
3548 if (((unchecked & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0) &&
3549 is_element) {
3550 // Normalize the elements to enable attributes on the property.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003551 NormalizeElements(js_object);
3552 Handle<NumberDictionary> dictionary(js_object->element_dictionary());
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003553 // Make sure that we never go back to fast case.
3554 dictionary->set_requires_slow_elements();
3555 PropertyDetails details = PropertyDetails(attr, NORMAL);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003556 NumberDictionarySet(dictionary, index, obj_value, details);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003557 }
3558
ager@chromium.org5c838252010-02-19 08:53:10 +00003559 LookupResult result;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003560 js_object->LookupRealNamedProperty(*name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00003561
ager@chromium.org5c838252010-02-19 08:53:10 +00003562 // Take special care when attributes are different and there is already
3563 // a property. For simplicity we normalize the property which enables us
3564 // to not worry about changing the instance_descriptor and creating a new
3565 // map. The current version of SetObjectProperty does not handle attributes
3566 // correctly in the case where a property is a field and is reset with
3567 // new attributes.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003568 if (result.IsProperty() &&
3569 (attr != result.GetAttributes() || result.type() == CALLBACKS)) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003570 // New attributes - normalize to avoid writing to instance descriptor
lrn@chromium.org303ada72010-10-27 09:33:13 +00003571 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00003572 // Use IgnoreAttributes version since a readonly property may be
3573 // overridden and SetProperty does not allow this.
3574 return js_object->IgnoreAttributesAndSetLocalProperty(*name,
3575 *obj_value,
3576 attr);
3577 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003578
ager@chromium.org5c838252010-02-19 08:53:10 +00003579 return Runtime::SetObjectProperty(js_object, name, obj_value, attr);
3580}
3581
3582
lrn@chromium.org303ada72010-10-27 09:33:13 +00003583MaybeObject* Runtime::SetObjectProperty(Handle<Object> object,
3584 Handle<Object> key,
3585 Handle<Object> value,
3586 PropertyAttributes attr) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003587 HandleScope scope;
3588
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003589 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003590 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003591 Handle<Object> error =
3592 Factory::NewTypeError("non_object_property_store",
3593 HandleVector(args, 2));
3594 return Top::Throw(*error);
3595 }
3596
3597 // If the object isn't a JavaScript object, we ignore the store.
3598 if (!object->IsJSObject()) return *value;
3599
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003600 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
3601
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003602 // Check if the given key is an array index.
3603 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003604 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003605 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
3606 // of a string using [] notation. We need to support this too in
3607 // JavaScript.
3608 // In the case of a String object we just need to redirect the assignment to
3609 // the underlying string if the index is in range. Since the underlying
3610 // string does nothing with the assignment then we can ignore such
3611 // assignments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003612 if (js_object->IsStringObjectWithCharacterAt(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003613 return *value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003614 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003615
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003616 Handle<Object> result = SetElement(js_object, index, value);
3617 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003618 return *value;
3619 }
3620
3621 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003622 Handle<Object> result;
3623 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003624 result = SetElement(js_object, index, value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003625 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003626 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003627 key_string->TryFlatten();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003628 result = SetProperty(js_object, key_string, value, attr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003629 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003630 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003631 return *value;
3632 }
3633
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003634 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003635 bool has_pending_exception = false;
3636 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
3637 if (has_pending_exception) return Failure::Exception();
3638 Handle<String> name = Handle<String>::cast(converted);
3639
3640 if (name->AsArrayIndex(&index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003641 return js_object->SetElement(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003642 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003643 return js_object->SetProperty(*name, *value, attr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003644 }
3645}
3646
3647
lrn@chromium.org303ada72010-10-27 09:33:13 +00003648MaybeObject* Runtime::ForceSetObjectProperty(Handle<JSObject> js_object,
3649 Handle<Object> key,
3650 Handle<Object> value,
3651 PropertyAttributes attr) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003652 HandleScope scope;
3653
3654 // Check if the given key is an array index.
3655 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003656 if (key->ToArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003657 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
3658 // of a string using [] notation. We need to support this too in
3659 // JavaScript.
3660 // In the case of a String object we just need to redirect the assignment to
3661 // the underlying string if the index is in range. Since the underlying
3662 // string does nothing with the assignment then we can ignore such
3663 // assignments.
3664 if (js_object->IsStringObjectWithCharacterAt(index)) {
3665 return *value;
3666 }
3667
3668 return js_object->SetElement(index, *value);
3669 }
3670
3671 if (key->IsString()) {
3672 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003673 return js_object->SetElement(index, *value);
3674 } else {
3675 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003676 key_string->TryFlatten();
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003677 return js_object->IgnoreAttributesAndSetLocalProperty(*key_string,
3678 *value,
3679 attr);
3680 }
3681 }
3682
3683 // Call-back into JavaScript to convert the key to a string.
3684 bool has_pending_exception = false;
3685 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
3686 if (has_pending_exception) return Failure::Exception();
3687 Handle<String> name = Handle<String>::cast(converted);
3688
3689 if (name->AsArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003690 return js_object->SetElement(index, *value);
3691 } else {
3692 return js_object->IgnoreAttributesAndSetLocalProperty(*name, *value, attr);
3693 }
3694}
3695
3696
lrn@chromium.org303ada72010-10-27 09:33:13 +00003697MaybeObject* Runtime::ForceDeleteObjectProperty(Handle<JSObject> js_object,
3698 Handle<Object> key) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00003699 HandleScope scope;
3700
3701 // Check if the given key is an array index.
3702 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003703 if (key->ToArrayIndex(&index)) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00003704 // In Firefox/SpiderMonkey, Safari and Opera you can access the
3705 // characters of a string using [] notation. In the case of a
3706 // String object we just need to redirect the deletion to the
3707 // underlying string if the index is in range. Since the
3708 // underlying string does nothing with the deletion, we can ignore
3709 // such deletions.
3710 if (js_object->IsStringObjectWithCharacterAt(index)) {
3711 return Heap::true_value();
3712 }
3713
3714 return js_object->DeleteElement(index, JSObject::FORCE_DELETION);
3715 }
3716
3717 Handle<String> key_string;
3718 if (key->IsString()) {
3719 key_string = Handle<String>::cast(key);
3720 } else {
3721 // Call-back into JavaScript to convert the key to a string.
3722 bool has_pending_exception = false;
3723 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
3724 if (has_pending_exception) return Failure::Exception();
3725 key_string = Handle<String>::cast(converted);
3726 }
3727
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003728 key_string->TryFlatten();
ager@chromium.orge2902be2009-06-08 12:21:35 +00003729 return js_object->DeleteProperty(*key_string, JSObject::FORCE_DELETION);
3730}
3731
3732
lrn@chromium.org303ada72010-10-27 09:33:13 +00003733static MaybeObject* Runtime_SetProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003734 NoHandleAllocation ha;
3735 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
3736
3737 Handle<Object> object = args.at<Object>(0);
3738 Handle<Object> key = args.at<Object>(1);
3739 Handle<Object> value = args.at<Object>(2);
3740
3741 // Compute attributes.
3742 PropertyAttributes attributes = NONE;
3743 if (args.length() == 4) {
3744 CONVERT_CHECKED(Smi, value_obj, args[3]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003745 int unchecked_value = value_obj->value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003746 // Only attribute bits should be set.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003747 RUNTIME_ASSERT(
3748 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3749 attributes = static_cast<PropertyAttributes>(unchecked_value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003750 }
3751 return Runtime::SetObjectProperty(object, key, value, attributes);
3752}
3753
3754
3755// Set a local property, even if it is READ_ONLY. If the property does not
3756// exist, it will be added with attributes NONE.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003757static MaybeObject* Runtime_IgnoreAttributesAndSetProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003758 NoHandleAllocation ha;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003759 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003760 CONVERT_CHECKED(JSObject, object, args[0]);
3761 CONVERT_CHECKED(String, name, args[1]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003762 // Compute attributes.
3763 PropertyAttributes attributes = NONE;
3764 if (args.length() == 4) {
3765 CONVERT_CHECKED(Smi, value_obj, args[3]);
3766 int unchecked_value = value_obj->value();
3767 // Only attribute bits should be set.
3768 RUNTIME_ASSERT(
3769 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3770 attributes = static_cast<PropertyAttributes>(unchecked_value);
3771 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003772
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003773 return object->
3774 IgnoreAttributesAndSetLocalProperty(name, args[2], attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003775}
3776
3777
lrn@chromium.org303ada72010-10-27 09:33:13 +00003778static MaybeObject* Runtime_DeleteProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003779 NoHandleAllocation ha;
3780 ASSERT(args.length() == 2);
3781
3782 CONVERT_CHECKED(JSObject, object, args[0]);
3783 CONVERT_CHECKED(String, key, args[1]);
ager@chromium.orge2902be2009-06-08 12:21:35 +00003784 return object->DeleteProperty(key, JSObject::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003785}
3786
3787
ager@chromium.org9085a012009-05-11 19:22:57 +00003788static Object* HasLocalPropertyImplementation(Handle<JSObject> object,
3789 Handle<String> key) {
3790 if (object->HasLocalProperty(*key)) return Heap::true_value();
3791 // Handle hidden prototypes. If there's a hidden prototype above this thing
3792 // then we have to check it for properties, because they are supposed to
3793 // look like they are on this object.
3794 Handle<Object> proto(object->GetPrototype());
3795 if (proto->IsJSObject() &&
3796 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
3797 return HasLocalPropertyImplementation(Handle<JSObject>::cast(proto), key);
3798 }
3799 return Heap::false_value();
3800}
3801
3802
lrn@chromium.org303ada72010-10-27 09:33:13 +00003803static MaybeObject* Runtime_HasLocalProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003804 NoHandleAllocation ha;
3805 ASSERT(args.length() == 2);
3806 CONVERT_CHECKED(String, key, args[1]);
3807
ager@chromium.org9085a012009-05-11 19:22:57 +00003808 Object* obj = args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003809 // Only JS objects can have properties.
ager@chromium.org9085a012009-05-11 19:22:57 +00003810 if (obj->IsJSObject()) {
3811 JSObject* object = JSObject::cast(obj);
3812 // Fast case - no interceptors.
3813 if (object->HasRealNamedProperty(key)) return Heap::true_value();
3814 // Slow case. Either it's not there or we have an interceptor. We should
3815 // have handles for this kind of deal.
3816 HandleScope scope;
3817 return HasLocalPropertyImplementation(Handle<JSObject>(object),
3818 Handle<String>(key));
3819 } else if (obj->IsString()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003820 // Well, there is one exception: Handle [] on strings.
3821 uint32_t index;
3822 if (key->AsArrayIndex(&index)) {
ager@chromium.org9085a012009-05-11 19:22:57 +00003823 String* string = String::cast(obj);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003824 if (index < static_cast<uint32_t>(string->length()))
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003825 return Heap::true_value();
3826 }
3827 }
3828 return Heap::false_value();
3829}
3830
3831
lrn@chromium.org303ada72010-10-27 09:33:13 +00003832static MaybeObject* Runtime_HasProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003833 NoHandleAllocation na;
3834 ASSERT(args.length() == 2);
3835
3836 // Only JS objects can have properties.
3837 if (args[0]->IsJSObject()) {
3838 JSObject* object = JSObject::cast(args[0]);
3839 CONVERT_CHECKED(String, key, args[1]);
3840 if (object->HasProperty(key)) return Heap::true_value();
3841 }
3842 return Heap::false_value();
3843}
3844
3845
lrn@chromium.org303ada72010-10-27 09:33:13 +00003846static MaybeObject* Runtime_HasElement(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003847 NoHandleAllocation na;
3848 ASSERT(args.length() == 2);
3849
3850 // Only JS objects can have elements.
3851 if (args[0]->IsJSObject()) {
3852 JSObject* object = JSObject::cast(args[0]);
3853 CONVERT_CHECKED(Smi, index_obj, args[1]);
3854 uint32_t index = index_obj->value();
3855 if (object->HasElement(index)) return Heap::true_value();
3856 }
3857 return Heap::false_value();
3858}
3859
3860
lrn@chromium.org303ada72010-10-27 09:33:13 +00003861static MaybeObject* Runtime_IsPropertyEnumerable(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003862 NoHandleAllocation ha;
3863 ASSERT(args.length() == 2);
3864
3865 CONVERT_CHECKED(JSObject, object, args[0]);
3866 CONVERT_CHECKED(String, key, args[1]);
3867
3868 uint32_t index;
3869 if (key->AsArrayIndex(&index)) {
3870 return Heap::ToBoolean(object->HasElement(index));
3871 }
3872
ager@chromium.org870a0b62008-11-04 11:43:05 +00003873 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
3874 return Heap::ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003875}
3876
3877
lrn@chromium.org303ada72010-10-27 09:33:13 +00003878static MaybeObject* Runtime_GetPropertyNames(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003879 HandleScope scope;
3880 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00003881 CONVERT_ARG_CHECKED(JSObject, object, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003882 return *GetKeysFor(object);
3883}
3884
3885
3886// Returns either a FixedArray as Runtime_GetPropertyNames,
3887// or, if the given object has an enum cache that contains
3888// all enumerable properties of the object and its prototypes
3889// have none, the map of the object. This is used to speed up
3890// the check for deletions during a for-in.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003891static MaybeObject* Runtime_GetPropertyNamesFast(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003892 ASSERT(args.length() == 1);
3893
3894 CONVERT_CHECKED(JSObject, raw_object, args[0]);
3895
3896 if (raw_object->IsSimpleEnum()) return raw_object->map();
3897
3898 HandleScope scope;
3899 Handle<JSObject> object(raw_object);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00003900 Handle<FixedArray> content = GetKeysInFixedArrayFor(object,
3901 INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003902
3903 // Test again, since cache may have been built by preceding call.
3904 if (object->IsSimpleEnum()) return object->map();
3905
3906 return *content;
3907}
3908
3909
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003910// Find the length of the prototype chain that is to to handled as one. If a
3911// prototype object is hidden it is to be viewed as part of the the object it
3912// is prototype for.
3913static int LocalPrototypeChainLength(JSObject* obj) {
3914 int count = 1;
3915 Object* proto = obj->GetPrototype();
3916 while (proto->IsJSObject() &&
3917 JSObject::cast(proto)->map()->is_hidden_prototype()) {
3918 count++;
3919 proto = JSObject::cast(proto)->GetPrototype();
3920 }
3921 return count;
3922}
3923
3924
3925// Return the names of the local named properties.
3926// args[0]: object
lrn@chromium.org303ada72010-10-27 09:33:13 +00003927static MaybeObject* Runtime_GetLocalPropertyNames(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003928 HandleScope scope;
3929 ASSERT(args.length() == 1);
3930 if (!args[0]->IsJSObject()) {
3931 return Heap::undefined_value();
3932 }
3933 CONVERT_ARG_CHECKED(JSObject, obj, 0);
3934
3935 // Skip the global proxy as it has no properties and always delegates to the
3936 // real global object.
3937 if (obj->IsJSGlobalProxy()) {
3938 // Only collect names if access is permitted.
3939 if (obj->IsAccessCheckNeeded() &&
3940 !Top::MayNamedAccess(*obj, Heap::undefined_value(), v8::ACCESS_KEYS)) {
3941 Top::ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
3942 return *Factory::NewJSArray(0);
3943 }
3944 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
3945 }
3946
3947 // Find the number of objects making up this.
3948 int length = LocalPrototypeChainLength(*obj);
3949
3950 // Find the number of local properties for each of the objects.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00003951 ScopedVector<int> local_property_count(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003952 int total_property_count = 0;
3953 Handle<JSObject> jsproto = obj;
3954 for (int i = 0; i < length; i++) {
3955 // Only collect names if access is permitted.
3956 if (jsproto->IsAccessCheckNeeded() &&
3957 !Top::MayNamedAccess(*jsproto,
3958 Heap::undefined_value(),
3959 v8::ACCESS_KEYS)) {
3960 Top::ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
3961 return *Factory::NewJSArray(0);
3962 }
3963 int n;
3964 n = jsproto->NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE));
3965 local_property_count[i] = n;
3966 total_property_count += n;
3967 if (i < length - 1) {
3968 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
3969 }
3970 }
3971
3972 // Allocate an array with storage for all the property names.
3973 Handle<FixedArray> names = Factory::NewFixedArray(total_property_count);
3974
3975 // Get the property names.
3976 jsproto = obj;
3977 int proto_with_hidden_properties = 0;
3978 for (int i = 0; i < length; i++) {
3979 jsproto->GetLocalPropertyNames(*names,
3980 i == 0 ? 0 : local_property_count[i - 1]);
3981 if (!GetHiddenProperties(jsproto, false)->IsUndefined()) {
3982 proto_with_hidden_properties++;
3983 }
3984 if (i < length - 1) {
3985 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
3986 }
3987 }
3988
3989 // Filter out name of hidden propeties object.
3990 if (proto_with_hidden_properties > 0) {
3991 Handle<FixedArray> old_names = names;
3992 names = Factory::NewFixedArray(
3993 names->length() - proto_with_hidden_properties);
3994 int dest_pos = 0;
3995 for (int i = 0; i < total_property_count; i++) {
3996 Object* name = old_names->get(i);
3997 if (name == Heap::hidden_symbol()) {
3998 continue;
3999 }
4000 names->set(dest_pos++, name);
4001 }
4002 }
4003
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004004 return *Factory::NewJSArrayWithElements(names);
4005}
4006
4007
4008// Return the names of the local indexed properties.
4009// args[0]: object
lrn@chromium.org303ada72010-10-27 09:33:13 +00004010static MaybeObject* Runtime_GetLocalElementNames(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004011 HandleScope scope;
4012 ASSERT(args.length() == 1);
4013 if (!args[0]->IsJSObject()) {
4014 return Heap::undefined_value();
4015 }
4016 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4017
4018 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
4019 Handle<FixedArray> names = Factory::NewFixedArray(n);
4020 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
4021 return *Factory::NewJSArrayWithElements(names);
4022}
4023
4024
4025// Return information on whether an object has a named or indexed interceptor.
4026// args[0]: object
lrn@chromium.org303ada72010-10-27 09:33:13 +00004027static MaybeObject* Runtime_GetInterceptorInfo(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004028 HandleScope scope;
4029 ASSERT(args.length() == 1);
4030 if (!args[0]->IsJSObject()) {
4031 return Smi::FromInt(0);
4032 }
4033 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4034
4035 int result = 0;
4036 if (obj->HasNamedInterceptor()) result |= 2;
4037 if (obj->HasIndexedInterceptor()) result |= 1;
4038
4039 return Smi::FromInt(result);
4040}
4041
4042
4043// Return property names from named interceptor.
4044// args[0]: object
lrn@chromium.org303ada72010-10-27 09:33:13 +00004045static MaybeObject* Runtime_GetNamedInterceptorPropertyNames(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004046 HandleScope scope;
4047 ASSERT(args.length() == 1);
4048 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4049
4050 if (obj->HasNamedInterceptor()) {
4051 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
4052 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4053 }
4054 return Heap::undefined_value();
4055}
4056
4057
4058// Return element names from indexed interceptor.
4059// args[0]: object
lrn@chromium.org303ada72010-10-27 09:33:13 +00004060static MaybeObject* Runtime_GetIndexedInterceptorElementNames(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004061 HandleScope scope;
4062 ASSERT(args.length() == 1);
4063 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4064
4065 if (obj->HasIndexedInterceptor()) {
4066 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
4067 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4068 }
4069 return Heap::undefined_value();
4070}
4071
4072
lrn@chromium.org303ada72010-10-27 09:33:13 +00004073static MaybeObject* Runtime_LocalKeys(Arguments args) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004074 ASSERT_EQ(args.length(), 1);
4075 CONVERT_CHECKED(JSObject, raw_object, args[0]);
4076 HandleScope scope;
4077 Handle<JSObject> object(raw_object);
4078 Handle<FixedArray> contents = GetKeysInFixedArrayFor(object,
4079 LOCAL_ONLY);
4080 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
4081 // property array and since the result is mutable we have to create
4082 // a fresh clone on each invocation.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004083 int length = contents->length();
4084 Handle<FixedArray> copy = Factory::NewFixedArray(length);
4085 for (int i = 0; i < length; i++) {
4086 Object* entry = contents->get(i);
4087 if (entry->IsString()) {
4088 copy->set(i, entry);
4089 } else {
4090 ASSERT(entry->IsNumber());
4091 HandleScope scope;
4092 Handle<Object> entry_handle(entry);
4093 Handle<Object> entry_str = Factory::NumberToString(entry_handle);
4094 copy->set(i, *entry_str);
4095 }
4096 }
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004097 return *Factory::NewJSArrayWithElements(copy);
4098}
4099
4100
lrn@chromium.org303ada72010-10-27 09:33:13 +00004101static MaybeObject* Runtime_GetArgumentsProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004102 NoHandleAllocation ha;
4103 ASSERT(args.length() == 1);
4104
4105 // Compute the frame holding the arguments.
4106 JavaScriptFrameIterator it;
4107 it.AdvanceToArgumentsFrame();
4108 JavaScriptFrame* frame = it.frame();
4109
4110 // Get the actual number of provided arguments.
4111 const uint32_t n = frame->GetProvidedParametersCount();
4112
4113 // Try to convert the key to an index. If successful and within
4114 // index return the the argument from the frame.
4115 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004116 if (args[0]->ToArrayIndex(&index) && index < n) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004117 return frame->GetParameter(index);
4118 }
4119
4120 // Convert the key to a string.
4121 HandleScope scope;
4122 bool exception = false;
4123 Handle<Object> converted =
4124 Execution::ToString(args.at<Object>(0), &exception);
4125 if (exception) return Failure::Exception();
4126 Handle<String> key = Handle<String>::cast(converted);
4127
4128 // Try to convert the string key into an array index.
4129 if (key->AsArrayIndex(&index)) {
4130 if (index < n) {
4131 return frame->GetParameter(index);
4132 } else {
4133 return Top::initial_object_prototype()->GetElement(index);
4134 }
4135 }
4136
4137 // Handle special arguments properties.
4138 if (key->Equals(Heap::length_symbol())) return Smi::FromInt(n);
4139 if (key->Equals(Heap::callee_symbol())) return frame->function();
4140
4141 // Lookup in the initial Object.prototype object.
4142 return Top::initial_object_prototype()->GetProperty(*key);
4143}
4144
4145
lrn@chromium.org303ada72010-10-27 09:33:13 +00004146static MaybeObject* Runtime_ToFastProperties(Arguments args) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004147 HandleScope scope;
4148
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004149 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004150 Handle<Object> object = args.at<Object>(0);
4151 if (object->IsJSObject()) {
4152 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
ager@chromium.org5c838252010-02-19 08:53:10 +00004153 if (!js_object->HasFastProperties() && !js_object->IsGlobalObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004154 MaybeObject* ok = js_object->TransformToFastProperties(0);
4155 if (ok->IsRetryAfterGC()) return ok;
ager@chromium.org5c838252010-02-19 08:53:10 +00004156 }
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004157 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004158 return *object;
4159}
4160
4161
lrn@chromium.org303ada72010-10-27 09:33:13 +00004162static MaybeObject* Runtime_ToSlowProperties(Arguments args) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004163 HandleScope scope;
4164
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004165 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004166 Handle<Object> object = args.at<Object>(0);
4167 if (object->IsJSObject()) {
4168 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004169 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004170 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004171 return *object;
4172}
4173
4174
lrn@chromium.org303ada72010-10-27 09:33:13 +00004175static MaybeObject* Runtime_ToBool(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004176 NoHandleAllocation ha;
4177 ASSERT(args.length() == 1);
4178
4179 return args[0]->ToBoolean();
4180}
4181
4182
4183// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
4184// Possible optimizations: put the type string into the oddballs.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004185static MaybeObject* Runtime_Typeof(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004186 NoHandleAllocation ha;
4187
4188 Object* obj = args[0];
4189 if (obj->IsNumber()) return Heap::number_symbol();
4190 HeapObject* heap_obj = HeapObject::cast(obj);
4191
4192 // typeof an undetectable object is 'undefined'
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004193 if (heap_obj->map()->is_undetectable()) return Heap::undefined_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004194
4195 InstanceType instance_type = heap_obj->map()->instance_type();
4196 if (instance_type < FIRST_NONSTRING_TYPE) {
4197 return Heap::string_symbol();
4198 }
4199
4200 switch (instance_type) {
4201 case ODDBALL_TYPE:
4202 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
4203 return Heap::boolean_symbol();
4204 }
4205 if (heap_obj->IsNull()) {
4206 return Heap::object_symbol();
4207 }
4208 ASSERT(heap_obj->IsUndefined());
4209 return Heap::undefined_symbol();
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00004210 case JS_FUNCTION_TYPE: case JS_REGEXP_TYPE:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004211 return Heap::function_symbol();
4212 default:
4213 // For any kind of object not handled above, the spec rule for
4214 // host objects gives that it is okay to return "object"
4215 return Heap::object_symbol();
4216 }
4217}
4218
4219
lrn@chromium.org25156de2010-04-06 13:10:27 +00004220static bool AreDigits(const char*s, int from, int to) {
4221 for (int i = from; i < to; i++) {
4222 if (s[i] < '0' || s[i] > '9') return false;
4223 }
4224
4225 return true;
4226}
4227
4228
4229static int ParseDecimalInteger(const char*s, int from, int to) {
4230 ASSERT(to - from < 10); // Overflow is not possible.
4231 ASSERT(from < to);
4232 int d = s[from] - '0';
4233
4234 for (int i = from + 1; i < to; i++) {
4235 d = 10 * d + (s[i] - '0');
4236 }
4237
4238 return d;
4239}
4240
4241
lrn@chromium.org303ada72010-10-27 09:33:13 +00004242static MaybeObject* Runtime_StringToNumber(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004243 NoHandleAllocation ha;
4244 ASSERT(args.length() == 1);
4245 CONVERT_CHECKED(String, subject, args[0]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004246 subject->TryFlatten();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004247
4248 // Fast case: short integer or some sorts of junk values.
4249 int len = subject->length();
4250 if (subject->IsSeqAsciiString()) {
4251 if (len == 0) return Smi::FromInt(0);
4252
4253 char const* data = SeqAsciiString::cast(subject)->GetChars();
4254 bool minus = (data[0] == '-');
4255 int start_pos = (minus ? 1 : 0);
4256
4257 if (start_pos == len) {
4258 return Heap::nan_value();
4259 } else if (data[start_pos] > '9') {
4260 // Fast check for a junk value. A valid string may start from a
4261 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
4262 // the 'I' character ('Infinity'). All of that have codes not greater than
4263 // '9' except 'I'.
4264 if (data[start_pos] != 'I') {
4265 return Heap::nan_value();
4266 }
4267 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
4268 // The maximal/minimal smi has 10 digits. If the string has less digits we
4269 // know it will fit into the smi-data type.
4270 int d = ParseDecimalInteger(data, start_pos, len);
4271 if (minus) {
4272 if (d == 0) return Heap::minus_zero_value();
4273 d = -d;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004274 } else if (!subject->HasHashCode() &&
4275 len <= String::kMaxArrayIndexSize &&
4276 (len == 1 || data[0] != '0')) {
4277 // String hash is not calculated yet but all the data are present.
4278 // Update the hash field to speed up sequential convertions.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00004279 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004280#ifdef DEBUG
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004281 subject->Hash(); // Force hash calculation.
4282 ASSERT_EQ(static_cast<int>(subject->hash_field()),
4283 static_cast<int>(hash));
4284#endif
4285 subject->set_hash_field(hash);
lrn@chromium.org25156de2010-04-06 13:10:27 +00004286 }
4287 return Smi::FromInt(d);
4288 }
4289 }
4290
4291 // Slower case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004292 return Heap::NumberFromDouble(StringToDouble(subject, ALLOW_HEX));
4293}
4294
4295
lrn@chromium.org303ada72010-10-27 09:33:13 +00004296static MaybeObject* Runtime_StringFromCharCodeArray(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004297 NoHandleAllocation ha;
4298 ASSERT(args.length() == 1);
4299
4300 CONVERT_CHECKED(JSArray, codes, args[0]);
4301 int length = Smi::cast(codes->length())->value();
4302
4303 // Check if the string can be ASCII.
4304 int i;
4305 for (i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004306 Object* element;
4307 { MaybeObject* maybe_element = codes->GetElement(i);
4308 // We probably can't get an exception here, but just in order to enforce
4309 // the checking of inputs in the runtime calls we check here.
4310 if (!maybe_element->ToObject(&element)) return maybe_element;
4311 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004312 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
4313 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
4314 break;
4315 }
4316
lrn@chromium.org303ada72010-10-27 09:33:13 +00004317 MaybeObject* maybe_object = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004318 if (i == length) { // The string is ASCII.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004319 maybe_object = Heap::AllocateRawAsciiString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004320 } else { // The string is not ASCII.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004321 maybe_object = Heap::AllocateRawTwoByteString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004322 }
4323
lrn@chromium.org303ada72010-10-27 09:33:13 +00004324 Object* object = NULL;
4325 if (!maybe_object->ToObject(&object)) return maybe_object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004326 String* result = String::cast(object);
4327 for (int i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004328 Object* element;
4329 { MaybeObject* maybe_element = codes->GetElement(i);
4330 if (!maybe_element->ToObject(&element)) return maybe_element;
4331 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004332 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004333 result->Set(i, chr & 0xffff);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004334 }
4335 return result;
4336}
4337
4338
4339// kNotEscaped is generated by the following:
4340//
4341// #!/bin/perl
4342// for (my $i = 0; $i < 256; $i++) {
4343// print "\n" if $i % 16 == 0;
4344// my $c = chr($i);
4345// my $escaped = 1;
4346// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
4347// print $escaped ? "0, " : "1, ";
4348// }
4349
4350
4351static bool IsNotEscaped(uint16_t character) {
4352 // Only for 8 bit characters, the rest are always escaped (in a different way)
4353 ASSERT(character < 256);
4354 static const char kNotEscaped[256] = {
4355 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4356 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4357 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
4358 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
4359 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4360 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
4361 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4362 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
4363 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4364 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4365 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4366 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4367 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4368 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4369 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4370 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4371 };
4372 return kNotEscaped[character] != 0;
4373}
4374
4375
lrn@chromium.org303ada72010-10-27 09:33:13 +00004376static MaybeObject* Runtime_URIEscape(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004377 const char hex_chars[] = "0123456789ABCDEF";
4378 NoHandleAllocation ha;
4379 ASSERT(args.length() == 1);
4380 CONVERT_CHECKED(String, source, args[0]);
4381
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004382 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004383
4384 int escaped_length = 0;
4385 int length = source->length();
4386 {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004387 Access<StringInputBuffer> buffer(&runtime_string_input_buffer);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004388 buffer->Reset(source);
4389 while (buffer->has_more()) {
4390 uint16_t character = buffer->GetNext();
4391 if (character >= 256) {
4392 escaped_length += 6;
4393 } else if (IsNotEscaped(character)) {
4394 escaped_length++;
4395 } else {
4396 escaped_length += 3;
4397 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004398 // We don't allow strings that are longer than a maximal length.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004399 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004400 if (escaped_length > String::kMaxLength) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004401 Top::context()->mark_out_of_memory();
4402 return Failure::OutOfMemoryException();
4403 }
4404 }
4405 }
4406 // No length change implies no change. Return original string if no change.
4407 if (escaped_length == length) {
4408 return source;
4409 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00004410 Object* o;
4411 { MaybeObject* maybe_o = Heap::AllocateRawAsciiString(escaped_length);
4412 if (!maybe_o->ToObject(&o)) return maybe_o;
4413 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004414 String* destination = String::cast(o);
4415 int dest_position = 0;
4416
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004417 Access<StringInputBuffer> buffer(&runtime_string_input_buffer);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004418 buffer->Rewind();
4419 while (buffer->has_more()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00004420 uint16_t chr = buffer->GetNext();
4421 if (chr >= 256) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004422 destination->Set(dest_position, '%');
4423 destination->Set(dest_position+1, 'u');
4424 destination->Set(dest_position+2, hex_chars[chr >> 12]);
4425 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]);
4426 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]);
4427 destination->Set(dest_position+5, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004428 dest_position += 6;
ager@chromium.org870a0b62008-11-04 11:43:05 +00004429 } else if (IsNotEscaped(chr)) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004430 destination->Set(dest_position, chr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004431 dest_position++;
4432 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004433 destination->Set(dest_position, '%');
4434 destination->Set(dest_position+1, hex_chars[chr >> 4]);
4435 destination->Set(dest_position+2, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004436 dest_position += 3;
4437 }
4438 }
4439 return destination;
4440}
4441
4442
4443static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
4444 static const signed char kHexValue['g'] = {
4445 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4446 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4447 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4448 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
4449 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4450 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4451 -1, 10, 11, 12, 13, 14, 15 };
4452
4453 if (character1 > 'f') return -1;
4454 int hi = kHexValue[character1];
4455 if (hi == -1) return -1;
4456 if (character2 > 'f') return -1;
4457 int lo = kHexValue[character2];
4458 if (lo == -1) return -1;
4459 return (hi << 4) + lo;
4460}
4461
4462
ager@chromium.org870a0b62008-11-04 11:43:05 +00004463static inline int Unescape(String* source,
ager@chromium.org870a0b62008-11-04 11:43:05 +00004464 int i,
4465 int length,
4466 int* step) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004467 uint16_t character = source->Get(i);
ager@chromium.org870a0b62008-11-04 11:43:05 +00004468 int32_t hi = 0;
4469 int32_t lo = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004470 if (character == '%' &&
4471 i <= length - 6 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004472 source->Get(i + 1) == 'u' &&
4473 (hi = TwoDigitHex(source->Get(i + 2),
4474 source->Get(i + 3))) != -1 &&
4475 (lo = TwoDigitHex(source->Get(i + 4),
4476 source->Get(i + 5))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004477 *step = 6;
4478 return (hi << 8) + lo;
4479 } else if (character == '%' &&
4480 i <= length - 3 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004481 (lo = TwoDigitHex(source->Get(i + 1),
4482 source->Get(i + 2))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004483 *step = 3;
4484 return lo;
4485 } else {
4486 *step = 1;
4487 return character;
4488 }
4489}
4490
4491
lrn@chromium.org303ada72010-10-27 09:33:13 +00004492static MaybeObject* Runtime_URIUnescape(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004493 NoHandleAllocation ha;
4494 ASSERT(args.length() == 1);
4495 CONVERT_CHECKED(String, source, args[0]);
4496
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004497 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004498
4499 bool ascii = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004500 int length = source->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004501
4502 int unescaped_length = 0;
4503 for (int i = 0; i < length; unescaped_length++) {
4504 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004505 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004506 ascii = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004507 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004508 i += step;
4509 }
4510
4511 // No length change implies no change. Return original string if no change.
4512 if (unescaped_length == length)
4513 return source;
4514
lrn@chromium.org303ada72010-10-27 09:33:13 +00004515 Object* o;
4516 { MaybeObject* maybe_o = ascii ?
4517 Heap::AllocateRawAsciiString(unescaped_length) :
4518 Heap::AllocateRawTwoByteString(unescaped_length);
4519 if (!maybe_o->ToObject(&o)) return maybe_o;
4520 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004521 String* destination = String::cast(o);
4522
4523 int dest_position = 0;
4524 for (int i = 0; i < length; dest_position++) {
4525 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004526 destination->Set(dest_position, Unescape(source, i, length, &step));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004527 i += step;
4528 }
4529 return destination;
4530}
4531
4532
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004533static const unsigned int kQuoteTableLength = 128u;
4534
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004535static const int kJsonQuotesCharactersPerEntry = 8;
4536static const char* const JsonQuotes =
4537 "\\u0000 \\u0001 \\u0002 \\u0003 "
4538 "\\u0004 \\u0005 \\u0006 \\u0007 "
4539 "\\b \\t \\n \\u000b "
4540 "\\f \\r \\u000e \\u000f "
4541 "\\u0010 \\u0011 \\u0012 \\u0013 "
4542 "\\u0014 \\u0015 \\u0016 \\u0017 "
4543 "\\u0018 \\u0019 \\u001a \\u001b "
4544 "\\u001c \\u001d \\u001e \\u001f "
4545 " ! \\\" # "
4546 "$ % & ' "
4547 "( ) * + "
4548 ", - . / "
4549 "0 1 2 3 "
4550 "4 5 6 7 "
4551 "8 9 : ; "
4552 "< = > ? "
4553 "@ A B C "
4554 "D E F G "
4555 "H I J K "
4556 "L M N O "
4557 "P Q R S "
4558 "T U V W "
4559 "X Y Z [ "
4560 "\\\\ ] ^ _ "
4561 "` a b c "
4562 "d e f g "
4563 "h i j k "
4564 "l m n o "
4565 "p q r s "
4566 "t u v w "
4567 "x y z { "
4568 "| } ~ \177 ";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004569
4570
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004571// For a string that is less than 32k characters it should always be
4572// possible to allocate it in new space.
4573static const int kMaxGuaranteedNewSpaceString = 32 * 1024;
4574
4575
4576// Doing JSON quoting cannot make the string more than this many times larger.
4577static const int kJsonQuoteWorstCaseBlowup = 6;
4578
4579
4580// Covers the entire ASCII range (all other characters are unchanged by JSON
4581// quoting).
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004582static const byte JsonQuoteLengths[kQuoteTableLength] = {
4583 6, 6, 6, 6, 6, 6, 6, 6,
4584 2, 2, 2, 6, 2, 2, 6, 6,
4585 6, 6, 6, 6, 6, 6, 6, 6,
4586 6, 6, 6, 6, 6, 6, 6, 6,
4587 1, 1, 2, 1, 1, 1, 1, 1,
4588 1, 1, 1, 1, 1, 1, 1, 1,
4589 1, 1, 1, 1, 1, 1, 1, 1,
4590 1, 1, 1, 1, 1, 1, 1, 1,
4591 1, 1, 1, 1, 1, 1, 1, 1,
4592 1, 1, 1, 1, 1, 1, 1, 1,
4593 1, 1, 1, 1, 1, 1, 1, 1,
4594 1, 1, 1, 1, 2, 1, 1, 1,
4595 1, 1, 1, 1, 1, 1, 1, 1,
4596 1, 1, 1, 1, 1, 1, 1, 1,
4597 1, 1, 1, 1, 1, 1, 1, 1,
4598 1, 1, 1, 1, 1, 1, 1, 1,
4599};
4600
4601
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004602template <typename StringType>
4603MaybeObject* AllocateRawString(int length);
4604
4605
4606template <>
4607MaybeObject* AllocateRawString<SeqTwoByteString>(int length) {
4608 return Heap::AllocateRawTwoByteString(length);
4609}
4610
4611
4612template <>
4613MaybeObject* AllocateRawString<SeqAsciiString>(int length) {
4614 return Heap::AllocateRawAsciiString(length);
4615}
4616
4617
4618template <typename Char, typename StringType>
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004619static MaybeObject* SlowQuoteJsonString(Vector<const Char> characters) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004620 int length = characters.length();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004621 const Char* read_cursor = characters.start();
4622 const Char* end = read_cursor + length;
4623 const int kSpaceForQuotes = 2;
4624 int quoted_length = kSpaceForQuotes;
4625 while (read_cursor < end) {
4626 Char c = *(read_cursor++);
4627 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
4628 quoted_length++;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004629 } else {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004630 quoted_length += JsonQuoteLengths[static_cast<unsigned>(c)];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004631 }
4632 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004633 MaybeObject* new_alloc = AllocateRawString<StringType>(quoted_length);
4634 Object* new_object;
4635 if (!new_alloc->ToObject(&new_object)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004636 return new_alloc;
4637 }
4638 StringType* new_string = StringType::cast(new_object);
4639
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004640 Char* write_cursor = reinterpret_cast<Char*>(
4641 new_string->address() + SeqAsciiString::kHeaderSize);
4642 *(write_cursor++) = '"';
4643
4644 read_cursor = characters.start();
4645 while (read_cursor < end) {
4646 Char c = *(read_cursor++);
4647 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
4648 *(write_cursor++) = c;
4649 } else {
4650 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
4651 const char* replacement = JsonQuotes +
4652 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
4653 for (int i = 0; i < len; i++) {
4654 *write_cursor++ = *replacement++;
4655 }
4656 }
4657 }
4658 *(write_cursor++) = '"';
4659 return new_string;
4660}
4661
4662
4663template <typename Char, typename StringType>
4664static MaybeObject* QuoteJsonString(Vector<const Char> characters) {
4665 int length = characters.length();
4666 Counters::quote_json_char_count.Increment(length);
4667 const int kSpaceForQuotes = 2;
4668 int worst_case_length = length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotes;
4669 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
4670 return SlowQuoteJsonString<Char, StringType>(characters);
4671 }
4672
4673 MaybeObject* new_alloc = AllocateRawString<StringType>(worst_case_length);
4674 Object* new_object;
4675 if (!new_alloc->ToObject(&new_object)) {
4676 return new_alloc;
4677 }
4678 if (!Heap::new_space()->Contains(new_object)) {
4679 // Even if our string is small enough to fit in new space we still have to
4680 // handle it being allocated in old space as may happen in the third
4681 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
4682 // CEntryStub::GenerateCore.
4683 return SlowQuoteJsonString<Char, StringType>(characters);
4684 }
4685 StringType* new_string = StringType::cast(new_object);
4686 ASSERT(Heap::new_space()->Contains(new_string));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004687
4688 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize);
4689 Char* write_cursor = reinterpret_cast<Char*>(
4690 new_string->address() + SeqAsciiString::kHeaderSize);
4691 *(write_cursor++) = '"';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004692
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004693 const Char* read_cursor = characters.start();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004694 const Char* end = read_cursor + length;
4695 while (read_cursor < end) {
4696 Char c = *(read_cursor++);
4697 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
4698 *(write_cursor++) = c;
4699 } else {
4700 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
4701 const char* replacement = JsonQuotes +
4702 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
4703 write_cursor[0] = replacement[0];
4704 if (len > 1) {
4705 write_cursor[1] = replacement[1];
4706 if (len > 2) {
4707 ASSERT(len == 6);
4708 write_cursor[2] = replacement[2];
4709 write_cursor[3] = replacement[3];
4710 write_cursor[4] = replacement[4];
4711 write_cursor[5] = replacement[5];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004712 }
4713 }
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004714 write_cursor += len;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004715 }
4716 }
4717 *(write_cursor++) = '"';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004718
4719 int final_length = static_cast<int>(
4720 write_cursor - reinterpret_cast<Char*>(
4721 new_string->address() + SeqAsciiString::kHeaderSize));
4722 Heap::new_space()->ShrinkStringAtAllocationBoundary<StringType>(new_string,
4723 final_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004724 return new_string;
4725}
4726
4727
4728static MaybeObject* Runtime_QuoteJSONString(Arguments args) {
4729 NoHandleAllocation ha;
4730 CONVERT_CHECKED(String, str, args[0]);
4731 if (!str->IsFlat()) {
4732 MaybeObject* try_flatten = str->TryFlatten();
4733 Object* flat;
4734 if (!try_flatten->ToObject(&flat)) {
4735 return try_flatten;
4736 }
4737 str = String::cast(flat);
4738 ASSERT(str->IsFlat());
4739 }
4740 if (str->IsTwoByteRepresentation()) {
4741 return QuoteJsonString<uc16, SeqTwoByteString>(str->ToUC16Vector());
4742 } else {
4743 return QuoteJsonString<char, SeqAsciiString>(str->ToAsciiVector());
4744 }
4745}
4746
4747
4748
lrn@chromium.org303ada72010-10-27 09:33:13 +00004749static MaybeObject* Runtime_StringParseInt(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004750 NoHandleAllocation ha;
4751
4752 CONVERT_CHECKED(String, s, args[0]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00004753 CONVERT_SMI_CHECKED(radix, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004754
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004755 s->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004756
lrn@chromium.org25156de2010-04-06 13:10:27 +00004757 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
4758 double value = StringToInt(s, radix);
4759 return Heap::NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004760}
4761
4762
lrn@chromium.org303ada72010-10-27 09:33:13 +00004763static MaybeObject* Runtime_StringParseFloat(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004764 NoHandleAllocation ha;
4765 CONVERT_CHECKED(String, str, args[0]);
4766
4767 // ECMA-262 section 15.1.2.3, empty string is NaN
4768 double value = StringToDouble(str, ALLOW_TRAILING_JUNK, OS::nan_value());
4769
4770 // Create a number object from the value.
4771 return Heap::NumberFromDouble(value);
4772}
4773
4774
4775static unibrow::Mapping<unibrow::ToUppercase, 128> to_upper_mapping;
4776static unibrow::Mapping<unibrow::ToLowercase, 128> to_lower_mapping;
4777
4778
4779template <class Converter>
lrn@chromium.org303ada72010-10-27 09:33:13 +00004780MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
4781 String* s,
4782 int length,
4783 int input_string_length,
4784 unibrow::Mapping<Converter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004785 // We try this twice, once with the assumption that the result is no longer
4786 // than the input and, if that assumption breaks, again with the exact
4787 // length. This may not be pretty, but it is nicer than what was here before
4788 // and I hereby claim my vaffel-is.
4789 //
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004790 // Allocate the resulting string.
4791 //
4792 // NOTE: This assumes that the upper/lower case of an ascii
4793 // character is also ascii. This is currently the case, but it
4794 // might break in the future if we implement more context and locale
4795 // dependent upper/lower conversions.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004796 Object* o;
4797 { MaybeObject* maybe_o = s->IsAsciiRepresentation()
4798 ? Heap::AllocateRawAsciiString(length)
4799 : Heap::AllocateRawTwoByteString(length);
4800 if (!maybe_o->ToObject(&o)) return maybe_o;
4801 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004802 String* result = String::cast(o);
4803 bool has_changed_character = false;
4804
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004805 // Convert all characters to upper case, assuming that they will fit
4806 // in the buffer
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004807 Access<StringInputBuffer> buffer(&runtime_string_input_buffer);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004808 buffer->Reset(s);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004809 unibrow::uchar chars[Converter::kMaxWidth];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004810 // We can assume that the string is not empty
4811 uc32 current = buffer->GetNext();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004812 for (int i = 0; i < length;) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00004813 bool has_next = buffer->has_more();
4814 uc32 next = has_next ? buffer->GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004815 int char_length = mapping->get(current, next, chars);
4816 if (char_length == 0) {
4817 // The case conversion of this character is the character itself.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004818 result->Set(i, current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004819 i++;
4820 } else if (char_length == 1) {
4821 // Common case: converting the letter resulted in one character.
4822 ASSERT(static_cast<uc32>(chars[0]) != current);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004823 result->Set(i, chars[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004824 has_changed_character = true;
4825 i++;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004826 } else if (length == input_string_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004827 // We've assumed that the result would be as long as the
4828 // input but here is a character that converts to several
4829 // characters. No matter, we calculate the exact length
4830 // of the result and try the whole thing again.
4831 //
4832 // Note that this leaves room for optimization. We could just
4833 // memcpy what we already have to the result string. Also,
4834 // the result string is the last object allocated we could
4835 // "realloc" it and probably, in the vast majority of cases,
4836 // extend the existing string to be able to hold the full
4837 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00004838 int next_length = 0;
4839 if (has_next) {
4840 next_length = mapping->get(next, 0, chars);
4841 if (next_length == 0) next_length = 1;
4842 }
4843 int current_length = i + char_length + next_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004844 while (buffer->has_more()) {
4845 current = buffer->GetNext();
ager@chromium.org7c537e22008-10-16 08:43:32 +00004846 // NOTE: we use 0 as the next character here because, while
4847 // the next character may affect what a character converts to,
4848 // it does not in any case affect the length of what it convert
4849 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004850 int char_length = mapping->get(current, 0, chars);
4851 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00004852 current_length += char_length;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004853 if (current_length > Smi::kMaxValue) {
4854 Top::context()->mark_out_of_memory();
4855 return Failure::OutOfMemoryException();
4856 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004857 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004858 // Try again with the real length.
4859 return Smi::FromInt(current_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004860 } else {
4861 for (int j = 0; j < char_length; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004862 result->Set(i, chars[j]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004863 i++;
4864 }
4865 has_changed_character = true;
4866 }
4867 current = next;
4868 }
4869 if (has_changed_character) {
4870 return result;
4871 } else {
4872 // If we didn't actually change anything in doing the conversion
4873 // we simple return the result and let the converted string
4874 // become garbage; there is no reason to keep two identical strings
4875 // alive.
4876 return s;
4877 }
4878}
4879
4880
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004881namespace {
4882
lrn@chromium.org303ada72010-10-27 09:33:13 +00004883static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF;
4884
4885
4886// Given a word and two range boundaries returns a word with high bit
4887// set in every byte iff the corresponding input byte was strictly in
4888// the range (m, n). All the other bits in the result are cleared.
4889// This function is only useful when it can be inlined and the
4890// boundaries are statically known.
4891// Requires: all bytes in the input word and the boundaries must be
4892// ascii (less than 0x7F).
4893static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
4894 // Every byte in an ascii string is less than or equal to 0x7F.
4895 ASSERT((w & (kOneInEveryByte * 0x7F)) == w);
4896 // Use strict inequalities since in edge cases the function could be
4897 // further simplified.
4898 ASSERT(0 < m && m < n && n < 0x7F);
4899 // Has high bit set in every w byte less than n.
4900 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w;
4901 // Has high bit set in every w byte greater than m.
4902 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m);
4903 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80));
4904}
4905
4906
4907enum AsciiCaseConversion {
4908 ASCII_TO_LOWER,
4909 ASCII_TO_UPPER
4910};
4911
4912
4913template <AsciiCaseConversion dir>
4914struct FastAsciiConverter {
4915 static bool Convert(char* dst, char* src, int length) {
4916#ifdef DEBUG
4917 char* saved_dst = dst;
4918 char* saved_src = src;
4919#endif
4920 // We rely on the distance between upper and lower case letters
4921 // being a known power of 2.
4922 ASSERT('a' - 'A' == (1 << 5));
4923 // Boundaries for the range of input characters than require conversion.
4924 const char lo = (dir == ASCII_TO_LOWER) ? 'A' - 1 : 'a' - 1;
4925 const char hi = (dir == ASCII_TO_LOWER) ? 'Z' + 1 : 'z' + 1;
4926 bool changed = false;
4927 char* const limit = src + length;
4928#ifdef V8_HOST_CAN_READ_UNALIGNED
4929 // Process the prefix of the input that requires no conversion one
4930 // (machine) word at a time.
4931 while (src <= limit - sizeof(uintptr_t)) {
4932 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
4933 if (AsciiRangeMask(w, lo, hi) != 0) {
4934 changed = true;
4935 break;
4936 }
4937 *reinterpret_cast<uintptr_t*>(dst) = w;
4938 src += sizeof(uintptr_t);
4939 dst += sizeof(uintptr_t);
4940 }
4941 // Process the remainder of the input performing conversion when
4942 // required one word at a time.
4943 while (src <= limit - sizeof(uintptr_t)) {
4944 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
4945 uintptr_t m = AsciiRangeMask(w, lo, hi);
4946 // The mask has high (7th) bit set in every byte that needs
4947 // conversion and we know that the distance between cases is
4948 // 1 << 5.
4949 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
4950 src += sizeof(uintptr_t);
4951 dst += sizeof(uintptr_t);
4952 }
4953#endif
4954 // Process the last few bytes of the input (or the whole input if
4955 // unaligned access is not supported).
4956 while (src < limit) {
4957 char c = *src;
4958 if (lo < c && c < hi) {
4959 c ^= (1 << 5);
4960 changed = true;
4961 }
4962 *dst = c;
4963 ++src;
4964 ++dst;
4965 }
4966#ifdef DEBUG
4967 CheckConvert(saved_dst, saved_src, length, changed);
4968#endif
4969 return changed;
4970 }
4971
4972#ifdef DEBUG
4973 static void CheckConvert(char* dst, char* src, int length, bool changed) {
4974 bool expected_changed = false;
4975 for (int i = 0; i < length; i++) {
4976 if (dst[i] == src[i]) continue;
4977 expected_changed = true;
4978 if (dir == ASCII_TO_LOWER) {
4979 ASSERT('A' <= src[i] && src[i] <= 'Z');
4980 ASSERT(dst[i] == src[i] + ('a' - 'A'));
4981 } else {
4982 ASSERT(dir == ASCII_TO_UPPER);
4983 ASSERT('a' <= src[i] && src[i] <= 'z');
4984 ASSERT(dst[i] == src[i] - ('a' - 'A'));
4985 }
4986 }
4987 ASSERT(expected_changed == changed);
4988 }
4989#endif
4990};
4991
4992
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004993struct ToLowerTraits {
4994 typedef unibrow::ToLowercase UnibrowConverter;
4995
lrn@chromium.org303ada72010-10-27 09:33:13 +00004996 typedef FastAsciiConverter<ASCII_TO_LOWER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004997};
4998
4999
5000struct ToUpperTraits {
5001 typedef unibrow::ToUppercase UnibrowConverter;
5002
lrn@chromium.org303ada72010-10-27 09:33:13 +00005003 typedef FastAsciiConverter<ASCII_TO_UPPER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005004};
5005
5006} // namespace
5007
5008
5009template <typename ConvertTraits>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005010MUST_USE_RESULT static MaybeObject* ConvertCase(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005011 Arguments args,
5012 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005013 NoHandleAllocation ha;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005014 CONVERT_CHECKED(String, s, args[0]);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005015 s = s->TryFlattenGetString();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005016
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005017 const int length = s->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005018 // Assume that the string is not empty; we need this assumption later
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005019 if (length == 0) return s;
5020
5021 // Simpler handling of ascii strings.
5022 //
5023 // NOTE: This assumes that the upper/lower case of an ascii
5024 // character is also ascii. This is currently the case, but it
5025 // might break in the future if we implement more context and locale
5026 // dependent upper/lower conversions.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005027 if (s->IsSeqAsciiString()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005028 Object* o;
5029 { MaybeObject* maybe_o = Heap::AllocateRawAsciiString(length);
5030 if (!maybe_o->ToObject(&o)) return maybe_o;
5031 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005032 SeqAsciiString* result = SeqAsciiString::cast(o);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005033 bool has_changed_character = ConvertTraits::AsciiConverter::Convert(
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005034 result->GetChars(), SeqAsciiString::cast(s)->GetChars(), length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005035 return has_changed_character ? result : s;
5036 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005037
lrn@chromium.org303ada72010-10-27 09:33:13 +00005038 Object* answer;
5039 { MaybeObject* maybe_answer = ConvertCaseHelper(s, length, length, mapping);
5040 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5041 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005042 if (answer->IsSmi()) {
5043 // Retry with correct length.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005044 { MaybeObject* maybe_answer =
5045 ConvertCaseHelper(s, Smi::cast(answer)->value(), length, mapping);
5046 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5047 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005048 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00005049 return answer;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005050}
5051
5052
lrn@chromium.org303ada72010-10-27 09:33:13 +00005053static MaybeObject* Runtime_StringToLowerCase(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005054 return ConvertCase<ToLowerTraits>(args, &to_lower_mapping);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005055}
5056
5057
lrn@chromium.org303ada72010-10-27 09:33:13 +00005058static MaybeObject* Runtime_StringToUpperCase(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005059 return ConvertCase<ToUpperTraits>(args, &to_upper_mapping);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005060}
5061
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005062
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005063static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
5064 return unibrow::WhiteSpace::Is(c) || c == 0x200b;
5065}
5066
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005067
lrn@chromium.org303ada72010-10-27 09:33:13 +00005068static MaybeObject* Runtime_StringTrim(Arguments args) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005069 NoHandleAllocation ha;
5070 ASSERT(args.length() == 3);
5071
5072 CONVERT_CHECKED(String, s, args[0]);
5073 CONVERT_BOOLEAN_CHECKED(trimLeft, args[1]);
5074 CONVERT_BOOLEAN_CHECKED(trimRight, args[2]);
5075
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005076 s->TryFlatten();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005077 int length = s->length();
5078
5079 int left = 0;
5080 if (trimLeft) {
5081 while (left < length && IsTrimWhiteSpace(s->Get(left))) {
5082 left++;
5083 }
5084 }
5085
5086 int right = length;
5087 if (trimRight) {
5088 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) {
5089 right--;
5090 }
5091 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005092 return s->SubString(left, right);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005093}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005094
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005095
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005096template <typename SubjectChar, typename PatternChar>
5097void FindStringIndices(Vector<const SubjectChar> subject,
5098 Vector<const PatternChar> pattern,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005099 ZoneList<int>* indices,
5100 unsigned int limit) {
5101 ASSERT(limit > 0);
5102 // Collect indices of pattern in subject, and the end-of-string index.
5103 // Stop after finding at most limit values.
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005104 StringSearch<PatternChar, SubjectChar> search(pattern);
5105 int pattern_length = pattern.length();
5106 int index = 0;
5107 while (limit > 0) {
5108 index = search.Search(subject, index);
5109 if (index < 0) return;
5110 indices->Add(index);
5111 index += pattern_length;
5112 limit--;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005113 }
5114}
5115
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005116
lrn@chromium.org303ada72010-10-27 09:33:13 +00005117static MaybeObject* Runtime_StringSplit(Arguments args) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005118 ASSERT(args.length() == 3);
5119 HandleScope handle_scope;
5120 CONVERT_ARG_CHECKED(String, subject, 0);
5121 CONVERT_ARG_CHECKED(String, pattern, 1);
5122 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
5123
5124 int subject_length = subject->length();
5125 int pattern_length = pattern->length();
5126 RUNTIME_ASSERT(pattern_length > 0);
5127
5128 // The limit can be very large (0xffffffffu), but since the pattern
5129 // isn't empty, we can never create more parts than ~half the length
5130 // of the subject.
5131
5132 if (!subject->IsFlat()) FlattenString(subject);
5133
5134 static const int kMaxInitialListCapacity = 16;
5135
5136 ZoneScope scope(DELETE_ON_EXIT);
5137
5138 // Find (up to limit) indices of separator and end-of-string in subject
5139 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
5140 ZoneList<int> indices(initial_capacity);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005141 if (!pattern->IsFlat()) FlattenString(pattern);
5142
5143 // No allocation block.
5144 {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005145 AssertNoAllocation nogc;
5146 if (subject->IsAsciiRepresentation()) {
5147 Vector<const char> subject_vector = subject->ToAsciiVector();
5148 if (pattern->IsAsciiRepresentation()) {
5149 FindStringIndices(subject_vector,
5150 pattern->ToAsciiVector(),
5151 &indices,
5152 limit);
5153 } else {
5154 FindStringIndices(subject_vector,
5155 pattern->ToUC16Vector(),
5156 &indices,
5157 limit);
5158 }
5159 } else {
5160 Vector<const uc16> subject_vector = subject->ToUC16Vector();
5161 if (pattern->IsAsciiRepresentation()) {
5162 FindStringIndices(subject_vector,
5163 pattern->ToAsciiVector(),
5164 &indices,
5165 limit);
5166 } else {
5167 FindStringIndices(subject_vector,
5168 pattern->ToUC16Vector(),
5169 &indices,
5170 limit);
5171 }
5172 }
5173 }
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005174
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005175 if (static_cast<uint32_t>(indices.length()) < limit) {
5176 indices.Add(subject_length);
5177 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005178
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005179 // The list indices now contains the end of each part to create.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005180
5181 // Create JSArray of substrings separated by separator.
5182 int part_count = indices.length();
5183
5184 Handle<JSArray> result = Factory::NewJSArray(part_count);
5185 result->set_length(Smi::FromInt(part_count));
5186
5187 ASSERT(result->HasFastElements());
5188
5189 if (part_count == 1 && indices.at(0) == subject_length) {
5190 FixedArray::cast(result->elements())->set(0, *subject);
5191 return *result;
5192 }
5193
5194 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
5195 int part_start = 0;
5196 for (int i = 0; i < part_count; i++) {
5197 HandleScope local_loop_handle;
5198 int part_end = indices.at(i);
5199 Handle<String> substring =
5200 Factory::NewSubString(subject, part_start, part_end);
5201 elements->set(i, *substring);
5202 part_start = part_end + pattern_length;
5203 }
5204
5205 return *result;
5206}
5207
5208
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005209// Copies ascii characters to the given fixed array looking up
5210// one-char strings in the cache. Gives up on the first char that is
5211// not in the cache and fills the remainder with smi zeros. Returns
5212// the length of the successfully copied prefix.
5213static int CopyCachedAsciiCharsToArray(const char* chars,
5214 FixedArray* elements,
5215 int length) {
5216 AssertNoAllocation nogc;
5217 FixedArray* ascii_cache = Heap::single_character_string_cache();
5218 Object* undefined = Heap::undefined_value();
5219 int i;
5220 for (i = 0; i < length; ++i) {
5221 Object* value = ascii_cache->get(chars[i]);
5222 if (value == undefined) break;
5223 ASSERT(!Heap::InNewSpace(value));
5224 elements->set(i, value, SKIP_WRITE_BARRIER);
5225 }
5226 if (i < length) {
5227 ASSERT(Smi::FromInt(0) == 0);
5228 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
5229 }
5230#ifdef DEBUG
5231 for (int j = 0; j < length; ++j) {
5232 Object* element = elements->get(j);
5233 ASSERT(element == Smi::FromInt(0) ||
5234 (element->IsString() && String::cast(element)->LooksValid()));
5235 }
5236#endif
5237 return i;
5238}
5239
5240
5241// Converts a String to JSArray.
5242// For example, "foo" => ["f", "o", "o"].
lrn@chromium.org303ada72010-10-27 09:33:13 +00005243static MaybeObject* Runtime_StringToArray(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005244 HandleScope scope;
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005245 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005246 CONVERT_ARG_CHECKED(String, s, 0);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005247 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005248
5249 s->TryFlatten();
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005250 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005251
5252 Handle<FixedArray> elements;
5253 if (s->IsFlat() && s->IsAsciiRepresentation()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005254 Object* obj;
5255 { MaybeObject* maybe_obj = Heap::AllocateUninitializedFixedArray(length);
5256 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5257 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005258 elements = Handle<FixedArray>(FixedArray::cast(obj));
5259
5260 Vector<const char> chars = s->ToAsciiVector();
5261 // Note, this will initialize all elements (not only the prefix)
5262 // to prevent GC from seeing partially initialized array.
5263 int num_copied_from_cache = CopyCachedAsciiCharsToArray(chars.start(),
5264 *elements,
5265 length);
5266
5267 for (int i = num_copied_from_cache; i < length; ++i) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00005268 Handle<Object> str = LookupSingleCharacterStringFromCode(chars[i]);
5269 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005270 }
5271 } else {
5272 elements = Factory::NewFixedArray(length);
5273 for (int i = 0; i < length; ++i) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00005274 Handle<Object> str = LookupSingleCharacterStringFromCode(s->Get(i));
5275 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005276 }
5277 }
5278
5279#ifdef DEBUG
5280 for (int i = 0; i < length; ++i) {
5281 ASSERT(String::cast(elements->get(i))->length() == 1);
5282 }
5283#endif
5284
5285 return *Factory::NewJSArrayWithElements(elements);
5286}
5287
5288
lrn@chromium.org303ada72010-10-27 09:33:13 +00005289static MaybeObject* Runtime_NewStringWrapper(Arguments args) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005290 NoHandleAllocation ha;
5291 ASSERT(args.length() == 1);
5292 CONVERT_CHECKED(String, value, args[0]);
5293 return value->ToObject();
5294}
5295
5296
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00005297bool Runtime::IsUpperCaseChar(uint16_t ch) {
5298 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
5299 int char_length = to_upper_mapping.get(ch, 0, chars);
5300 return char_length == 0;
5301}
5302
5303
lrn@chromium.org303ada72010-10-27 09:33:13 +00005304static MaybeObject* Runtime_NumberToString(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005305 NoHandleAllocation ha;
5306 ASSERT(args.length() == 1);
5307
5308 Object* number = args[0];
5309 RUNTIME_ASSERT(number->IsNumber());
5310
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005311 return Heap::NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005312}
5313
5314
lrn@chromium.org303ada72010-10-27 09:33:13 +00005315static MaybeObject* Runtime_NumberToStringSkipCache(Arguments args) {
ager@chromium.org357bf652010-04-12 11:30:10 +00005316 NoHandleAllocation ha;
5317 ASSERT(args.length() == 1);
5318
5319 Object* number = args[0];
5320 RUNTIME_ASSERT(number->IsNumber());
5321
5322 return Heap::NumberToString(number, false);
5323}
5324
5325
lrn@chromium.org303ada72010-10-27 09:33:13 +00005326static MaybeObject* Runtime_NumberToInteger(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005327 NoHandleAllocation ha;
5328 ASSERT(args.length() == 1);
5329
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005330 CONVERT_DOUBLE_CHECKED(number, args[0]);
5331
5332 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5333 if (number > 0 && number <= Smi::kMaxValue) {
5334 return Smi::FromInt(static_cast<int>(number));
5335 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005336 return Heap::NumberFromDouble(DoubleToInteger(number));
5337}
5338
5339
lrn@chromium.org303ada72010-10-27 09:33:13 +00005340static MaybeObject* Runtime_NumberToIntegerMapMinusZero(Arguments args) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005341 NoHandleAllocation ha;
5342 ASSERT(args.length() == 1);
5343
5344 CONVERT_DOUBLE_CHECKED(number, args[0]);
5345
5346 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5347 if (number > 0 && number <= Smi::kMaxValue) {
5348 return Smi::FromInt(static_cast<int>(number));
5349 }
5350
5351 double double_value = DoubleToInteger(number);
5352 // Map both -0 and +0 to +0.
5353 if (double_value == 0) double_value = 0;
5354
5355 return Heap::NumberFromDouble(double_value);
5356}
5357
5358
lrn@chromium.org303ada72010-10-27 09:33:13 +00005359static MaybeObject* Runtime_NumberToJSUint32(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005360 NoHandleAllocation ha;
5361 ASSERT(args.length() == 1);
5362
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005363 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005364 return Heap::NumberFromUint32(number);
5365}
5366
5367
lrn@chromium.org303ada72010-10-27 09:33:13 +00005368static MaybeObject* Runtime_NumberToJSInt32(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005369 NoHandleAllocation ha;
5370 ASSERT(args.length() == 1);
5371
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005372 CONVERT_DOUBLE_CHECKED(number, args[0]);
5373
5374 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5375 if (number > 0 && number <= Smi::kMaxValue) {
5376 return Smi::FromInt(static_cast<int>(number));
5377 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005378 return Heap::NumberFromInt32(DoubleToInt32(number));
5379}
5380
5381
ager@chromium.org870a0b62008-11-04 11:43:05 +00005382// Converts a Number to a Smi, if possible. Returns NaN if the number is not
5383// a small integer.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005384static MaybeObject* Runtime_NumberToSmi(Arguments args) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00005385 NoHandleAllocation ha;
5386 ASSERT(args.length() == 1);
5387
5388 Object* obj = args[0];
5389 if (obj->IsSmi()) {
5390 return obj;
5391 }
5392 if (obj->IsHeapNumber()) {
5393 double value = HeapNumber::cast(obj)->value();
5394 int int_value = FastD2I(value);
5395 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
5396 return Smi::FromInt(int_value);
5397 }
5398 }
5399 return Heap::nan_value();
5400}
5401
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005402
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005403static MaybeObject* Runtime_AllocateHeapNumber(Arguments args) {
5404 NoHandleAllocation ha;
5405 ASSERT(args.length() == 0);
5406 return Heap::AllocateHeapNumber(0);
5407}
5408
5409
lrn@chromium.org303ada72010-10-27 09:33:13 +00005410static MaybeObject* Runtime_NumberAdd(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005411 NoHandleAllocation ha;
5412 ASSERT(args.length() == 2);
5413
5414 CONVERT_DOUBLE_CHECKED(x, args[0]);
5415 CONVERT_DOUBLE_CHECKED(y, args[1]);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00005416 return Heap::NumberFromDouble(x + y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005417}
5418
5419
lrn@chromium.org303ada72010-10-27 09:33:13 +00005420static MaybeObject* Runtime_NumberSub(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005421 NoHandleAllocation ha;
5422 ASSERT(args.length() == 2);
5423
5424 CONVERT_DOUBLE_CHECKED(x, args[0]);
5425 CONVERT_DOUBLE_CHECKED(y, args[1]);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00005426 return Heap::NumberFromDouble(x - y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005427}
5428
5429
lrn@chromium.org303ada72010-10-27 09:33:13 +00005430static MaybeObject* Runtime_NumberMul(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005431 NoHandleAllocation ha;
5432 ASSERT(args.length() == 2);
5433
5434 CONVERT_DOUBLE_CHECKED(x, args[0]);
5435 CONVERT_DOUBLE_CHECKED(y, args[1]);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00005436 return Heap::NumberFromDouble(x * y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005437}
5438
5439
lrn@chromium.org303ada72010-10-27 09:33:13 +00005440static MaybeObject* Runtime_NumberUnaryMinus(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005441 NoHandleAllocation ha;
5442 ASSERT(args.length() == 1);
5443
5444 CONVERT_DOUBLE_CHECKED(x, args[0]);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00005445 return Heap::NumberFromDouble(-x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005446}
5447
5448
lrn@chromium.org303ada72010-10-27 09:33:13 +00005449static MaybeObject* Runtime_NumberAlloc(Arguments args) {
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00005450 NoHandleAllocation ha;
5451 ASSERT(args.length() == 0);
5452
5453 return Heap::NumberFromDouble(9876543210.0);
5454}
5455
5456
lrn@chromium.org303ada72010-10-27 09:33:13 +00005457static MaybeObject* Runtime_NumberDiv(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005458 NoHandleAllocation ha;
5459 ASSERT(args.length() == 2);
5460
5461 CONVERT_DOUBLE_CHECKED(x, args[0]);
5462 CONVERT_DOUBLE_CHECKED(y, args[1]);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00005463 return Heap::NumberFromDouble(x / y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005464}
5465
5466
lrn@chromium.org303ada72010-10-27 09:33:13 +00005467static MaybeObject* Runtime_NumberMod(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005468 NoHandleAllocation ha;
5469 ASSERT(args.length() == 2);
5470
5471 CONVERT_DOUBLE_CHECKED(x, args[0]);
5472 CONVERT_DOUBLE_CHECKED(y, args[1]);
5473
ager@chromium.org3811b432009-10-28 14:53:37 +00005474 x = modulo(x, y);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00005475 // NumberFromDouble may return a Smi instead of a Number object
5476 return Heap::NumberFromDouble(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005477}
5478
5479
lrn@chromium.org303ada72010-10-27 09:33:13 +00005480static MaybeObject* Runtime_StringAdd(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005481 NoHandleAllocation ha;
5482 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005483 CONVERT_CHECKED(String, str1, args[0]);
5484 CONVERT_CHECKED(String, str2, args[1]);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00005485 Counters::string_add_runtime.Increment();
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00005486 return Heap::AllocateConsString(str1, str2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005487}
5488
5489
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005490template <typename sinkchar>
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005491static inline void StringBuilderConcatHelper(String* special,
5492 sinkchar* sink,
5493 FixedArray* fixed_array,
5494 int array_length) {
5495 int position = 0;
5496 for (int i = 0; i < array_length; i++) {
5497 Object* element = fixed_array->get(i);
5498 if (element->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005499 // Smi encoding of position and length.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005500 int encoded_slice = Smi::cast(element)->value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005501 int pos;
5502 int len;
5503 if (encoded_slice > 0) {
5504 // Position and length encoded in one smi.
5505 pos = StringBuilderSubstringPosition::decode(encoded_slice);
5506 len = StringBuilderSubstringLength::decode(encoded_slice);
5507 } else {
5508 // Position and length encoded in two smis.
5509 Object* obj = fixed_array->get(++i);
5510 ASSERT(obj->IsSmi());
5511 pos = Smi::cast(obj)->value();
5512 len = -encoded_slice;
5513 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00005514 String::WriteToFlat(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00005515 sink + position,
5516 pos,
5517 pos + len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005518 position += len;
5519 } else {
5520 String* string = String::cast(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005521 int element_length = string->length();
5522 String::WriteToFlat(string, sink + position, 0, element_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005523 position += element_length;
5524 }
5525 }
5526}
5527
5528
lrn@chromium.org303ada72010-10-27 09:33:13 +00005529static MaybeObject* Runtime_StringBuilderConcat(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005530 NoHandleAllocation ha;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005531 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005532 CONVERT_CHECKED(JSArray, array, args[0]);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005533 if (!args[1]->IsSmi()) {
5534 Top::context()->mark_out_of_memory();
5535 return Failure::OutOfMemoryException();
5536 }
5537 int array_length = Smi::cast(args[1])->value();
5538 CONVERT_CHECKED(String, special, args[2]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005539
5540 // This assumption is used by the slice encoding in one or two smis.
5541 ASSERT(Smi::kMaxValue >= String::kMaxLength);
5542
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005543 int special_length = special->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005544 if (!array->HasFastElements()) {
5545 return Top::Throw(Heap::illegal_argument_symbol());
5546 }
5547 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005548 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005549 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005550 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005551
5552 if (array_length == 0) {
5553 return Heap::empty_string();
5554 } else if (array_length == 1) {
5555 Object* first = fixed_array->get(0);
5556 if (first->IsString()) return first;
5557 }
5558
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005559 bool ascii = special->HasOnlyAsciiChars();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005560 int position = 0;
5561 for (int i = 0; i < array_length; i++) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005562 int increment = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005563 Object* elt = fixed_array->get(i);
5564 if (elt->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005565 // Smi encoding of position and length.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005566 int smi_value = Smi::cast(elt)->value();
5567 int pos;
5568 int len;
5569 if (smi_value > 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005570 // Position and length encoded in one smi.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005571 pos = StringBuilderSubstringPosition::decode(smi_value);
5572 len = StringBuilderSubstringLength::decode(smi_value);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005573 } else {
5574 // Position and length encoded in two smis.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005575 len = -smi_value;
5576 // Get the position and check that it is a positive smi.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005577 i++;
5578 if (i >= array_length) {
5579 return Top::Throw(Heap::illegal_argument_symbol());
5580 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005581 Object* next_smi = fixed_array->get(i);
5582 if (!next_smi->IsSmi()) {
5583 return Top::Throw(Heap::illegal_argument_symbol());
5584 }
5585 pos = Smi::cast(next_smi)->value();
5586 if (pos < 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005587 return Top::Throw(Heap::illegal_argument_symbol());
5588 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005589 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005590 ASSERT(pos >= 0);
5591 ASSERT(len >= 0);
5592 if (pos > special_length || len > special_length - pos) {
5593 return Top::Throw(Heap::illegal_argument_symbol());
5594 }
5595 increment = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005596 } else if (elt->IsString()) {
5597 String* element = String::cast(elt);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005598 int element_length = element->length();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005599 increment = element_length;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005600 if (ascii && !element->HasOnlyAsciiChars()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005601 ascii = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005602 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005603 } else {
5604 return Top::Throw(Heap::illegal_argument_symbol());
5605 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005606 if (increment > String::kMaxLength - position) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005607 Top::context()->mark_out_of_memory();
5608 return Failure::OutOfMemoryException();
5609 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005610 position += increment;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005611 }
5612
5613 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005614 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005615
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005616 if (ascii) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005617 { MaybeObject* maybe_object = Heap::AllocateRawAsciiString(length);
5618 if (!maybe_object->ToObject(&object)) return maybe_object;
5619 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005620 SeqAsciiString* answer = SeqAsciiString::cast(object);
5621 StringBuilderConcatHelper(special,
5622 answer->GetChars(),
5623 fixed_array,
5624 array_length);
5625 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005626 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005627 { MaybeObject* maybe_object = Heap::AllocateRawTwoByteString(length);
5628 if (!maybe_object->ToObject(&object)) return maybe_object;
5629 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005630 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
5631 StringBuilderConcatHelper(special,
5632 answer->GetChars(),
5633 fixed_array,
5634 array_length);
5635 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005636 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005637}
5638
5639
lrn@chromium.org303ada72010-10-27 09:33:13 +00005640static MaybeObject* Runtime_NumberOr(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005641 NoHandleAllocation ha;
5642 ASSERT(args.length() == 2);
5643
5644 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5645 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5646 return Heap::NumberFromInt32(x | y);
5647}
5648
5649
lrn@chromium.org303ada72010-10-27 09:33:13 +00005650static MaybeObject* Runtime_NumberAnd(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005651 NoHandleAllocation ha;
5652 ASSERT(args.length() == 2);
5653
5654 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5655 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5656 return Heap::NumberFromInt32(x & y);
5657}
5658
5659
lrn@chromium.org303ada72010-10-27 09:33:13 +00005660static MaybeObject* Runtime_NumberXor(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005661 NoHandleAllocation ha;
5662 ASSERT(args.length() == 2);
5663
5664 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5665 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5666 return Heap::NumberFromInt32(x ^ y);
5667}
5668
5669
lrn@chromium.org303ada72010-10-27 09:33:13 +00005670static MaybeObject* Runtime_NumberNot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005671 NoHandleAllocation ha;
5672 ASSERT(args.length() == 1);
5673
5674 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5675 return Heap::NumberFromInt32(~x);
5676}
5677
5678
lrn@chromium.org303ada72010-10-27 09:33:13 +00005679static MaybeObject* Runtime_NumberShl(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005680 NoHandleAllocation ha;
5681 ASSERT(args.length() == 2);
5682
5683 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5684 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5685 return Heap::NumberFromInt32(x << (y & 0x1f));
5686}
5687
5688
lrn@chromium.org303ada72010-10-27 09:33:13 +00005689static MaybeObject* Runtime_NumberShr(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005690 NoHandleAllocation ha;
5691 ASSERT(args.length() == 2);
5692
5693 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
5694 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5695 return Heap::NumberFromUint32(x >> (y & 0x1f));
5696}
5697
5698
lrn@chromium.org303ada72010-10-27 09:33:13 +00005699static MaybeObject* Runtime_NumberSar(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005700 NoHandleAllocation ha;
5701 ASSERT(args.length() == 2);
5702
5703 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5704 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5705 return Heap::NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
5706}
5707
5708
lrn@chromium.org303ada72010-10-27 09:33:13 +00005709static MaybeObject* Runtime_NumberEquals(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005710 NoHandleAllocation ha;
5711 ASSERT(args.length() == 2);
5712
5713 CONVERT_DOUBLE_CHECKED(x, args[0]);
5714 CONVERT_DOUBLE_CHECKED(y, args[1]);
5715 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
5716 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
5717 if (x == y) return Smi::FromInt(EQUAL);
5718 Object* result;
5719 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
5720 result = Smi::FromInt(EQUAL);
5721 } else {
5722 result = Smi::FromInt(NOT_EQUAL);
5723 }
5724 return result;
5725}
5726
5727
lrn@chromium.org303ada72010-10-27 09:33:13 +00005728static MaybeObject* Runtime_StringEquals(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005729 NoHandleAllocation ha;
5730 ASSERT(args.length() == 2);
5731
5732 CONVERT_CHECKED(String, x, args[0]);
5733 CONVERT_CHECKED(String, y, args[1]);
5734
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005735 bool not_equal = !x->Equals(y);
5736 // This is slightly convoluted because the value that signifies
5737 // equality is 0 and inequality is 1 so we have to negate the result
5738 // from String::Equals.
5739 ASSERT(not_equal == 0 || not_equal == 1);
5740 STATIC_CHECK(EQUAL == 0);
5741 STATIC_CHECK(NOT_EQUAL == 1);
5742 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005743}
5744
5745
lrn@chromium.org303ada72010-10-27 09:33:13 +00005746static MaybeObject* Runtime_NumberCompare(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005747 NoHandleAllocation ha;
5748 ASSERT(args.length() == 3);
5749
5750 CONVERT_DOUBLE_CHECKED(x, args[0]);
5751 CONVERT_DOUBLE_CHECKED(y, args[1]);
5752 if (isnan(x) || isnan(y)) return args[2];
5753 if (x == y) return Smi::FromInt(EQUAL);
5754 if (isless(x, y)) return Smi::FromInt(LESS);
5755 return Smi::FromInt(GREATER);
5756}
5757
5758
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005759// Compare two Smis as if they were converted to strings and then
5760// compared lexicographically.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005761static MaybeObject* Runtime_SmiLexicographicCompare(Arguments args) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005762 NoHandleAllocation ha;
5763 ASSERT(args.length() == 2);
5764
5765 // Arrays for the individual characters of the two Smis. Smis are
5766 // 31 bit integers and 10 decimal digits are therefore enough.
5767 static int x_elms[10];
5768 static int y_elms[10];
5769
5770 // Extract the integer values from the Smis.
5771 CONVERT_CHECKED(Smi, x, args[0]);
5772 CONVERT_CHECKED(Smi, y, args[1]);
5773 int x_value = x->value();
5774 int y_value = y->value();
5775
5776 // If the integers are equal so are the string representations.
5777 if (x_value == y_value) return Smi::FromInt(EQUAL);
5778
5779 // If one of the integers are zero the normal integer order is the
5780 // same as the lexicographic order of the string representations.
5781 if (x_value == 0 || y_value == 0) return Smi::FromInt(x_value - y_value);
5782
ager@chromium.org32912102009-01-16 10:38:43 +00005783 // If only one of the integers is negative the negative number is
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005784 // smallest because the char code of '-' is less than the char code
5785 // of any digit. Otherwise, we make both values positive.
5786 if (x_value < 0 || y_value < 0) {
5787 if (y_value >= 0) return Smi::FromInt(LESS);
5788 if (x_value >= 0) return Smi::FromInt(GREATER);
5789 x_value = -x_value;
5790 y_value = -y_value;
5791 }
5792
5793 // Convert the integers to arrays of their decimal digits.
5794 int x_index = 0;
5795 int y_index = 0;
5796 while (x_value > 0) {
5797 x_elms[x_index++] = x_value % 10;
5798 x_value /= 10;
5799 }
5800 while (y_value > 0) {
5801 y_elms[y_index++] = y_value % 10;
5802 y_value /= 10;
5803 }
5804
5805 // Loop through the arrays of decimal digits finding the first place
5806 // where they differ.
5807 while (--x_index >= 0 && --y_index >= 0) {
5808 int diff = x_elms[x_index] - y_elms[y_index];
5809 if (diff != 0) return Smi::FromInt(diff);
5810 }
5811
5812 // If one array is a suffix of the other array, the longest array is
5813 // the representation of the largest of the Smis in the
5814 // lexicographic ordering.
5815 return Smi::FromInt(x_index - y_index);
5816}
5817
5818
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005819static Object* StringInputBufferCompare(String* x, String* y) {
5820 static StringInputBuffer bufx;
5821 static StringInputBuffer bufy;
5822 bufx.Reset(x);
5823 bufy.Reset(y);
5824 while (bufx.has_more() && bufy.has_more()) {
5825 int d = bufx.GetNext() - bufy.GetNext();
5826 if (d < 0) return Smi::FromInt(LESS);
5827 else if (d > 0) return Smi::FromInt(GREATER);
5828 }
5829
5830 // x is (non-trivial) prefix of y:
5831 if (bufy.has_more()) return Smi::FromInt(LESS);
5832 // y is prefix of x:
5833 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
5834}
5835
5836
5837static Object* FlatStringCompare(String* x, String* y) {
5838 ASSERT(x->IsFlat());
5839 ASSERT(y->IsFlat());
5840 Object* equal_prefix_result = Smi::FromInt(EQUAL);
5841 int prefix_length = x->length();
5842 if (y->length() < prefix_length) {
5843 prefix_length = y->length();
5844 equal_prefix_result = Smi::FromInt(GREATER);
5845 } else if (y->length() > prefix_length) {
5846 equal_prefix_result = Smi::FromInt(LESS);
5847 }
5848 int r;
5849 if (x->IsAsciiRepresentation()) {
5850 Vector<const char> x_chars = x->ToAsciiVector();
5851 if (y->IsAsciiRepresentation()) {
5852 Vector<const char> y_chars = y->ToAsciiVector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005853 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005854 } else {
5855 Vector<const uc16> y_chars = y->ToUC16Vector();
5856 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
5857 }
5858 } else {
5859 Vector<const uc16> x_chars = x->ToUC16Vector();
5860 if (y->IsAsciiRepresentation()) {
5861 Vector<const char> y_chars = y->ToAsciiVector();
5862 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
5863 } else {
5864 Vector<const uc16> y_chars = y->ToUC16Vector();
5865 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
5866 }
5867 }
5868 Object* result;
5869 if (r == 0) {
5870 result = equal_prefix_result;
5871 } else {
5872 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
5873 }
5874 ASSERT(result == StringInputBufferCompare(x, y));
5875 return result;
5876}
5877
5878
lrn@chromium.org303ada72010-10-27 09:33:13 +00005879static MaybeObject* Runtime_StringCompare(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005880 NoHandleAllocation ha;
5881 ASSERT(args.length() == 2);
5882
5883 CONVERT_CHECKED(String, x, args[0]);
5884 CONVERT_CHECKED(String, y, args[1]);
5885
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005886 Counters::string_compare_runtime.Increment();
5887
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005888 // A few fast case tests before we flatten.
5889 if (x == y) return Smi::FromInt(EQUAL);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005890 if (y->length() == 0) {
5891 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005892 return Smi::FromInt(GREATER);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005893 } else if (x->length() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005894 return Smi::FromInt(LESS);
5895 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005896
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005897 int d = x->Get(0) - y->Get(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005898 if (d < 0) return Smi::FromInt(LESS);
5899 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005900
lrn@chromium.org303ada72010-10-27 09:33:13 +00005901 Object* obj;
5902 { MaybeObject* maybe_obj = Heap::PrepareForCompare(x);
5903 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5904 }
5905 { MaybeObject* maybe_obj = Heap::PrepareForCompare(y);
5906 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5907 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005908
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005909 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
5910 : StringInputBufferCompare(x, y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005911}
5912
5913
lrn@chromium.org303ada72010-10-27 09:33:13 +00005914static MaybeObject* Runtime_Math_acos(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005915 NoHandleAllocation ha;
5916 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005917 Counters::math_acos.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005918
5919 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005920 return TranscendentalCache::Get(TranscendentalCache::ACOS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005921}
5922
5923
lrn@chromium.org303ada72010-10-27 09:33:13 +00005924static MaybeObject* Runtime_Math_asin(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005925 NoHandleAllocation ha;
5926 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005927 Counters::math_asin.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005928
5929 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005930 return TranscendentalCache::Get(TranscendentalCache::ASIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005931}
5932
5933
lrn@chromium.org303ada72010-10-27 09:33:13 +00005934static MaybeObject* Runtime_Math_atan(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_atan.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005938
5939 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005940 return TranscendentalCache::Get(TranscendentalCache::ATAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005941}
5942
5943
lrn@chromium.org303ada72010-10-27 09:33:13 +00005944static MaybeObject* Runtime_Math_atan2(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005945 NoHandleAllocation ha;
5946 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005947 Counters::math_atan2.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005948
5949 CONVERT_DOUBLE_CHECKED(x, args[0]);
5950 CONVERT_DOUBLE_CHECKED(y, args[1]);
5951 double result;
5952 if (isinf(x) && isinf(y)) {
5953 // Make sure that the result in case of two infinite arguments
5954 // is a multiple of Pi / 4. The sign of the result is determined
5955 // by the first argument (x) and the sign of the second argument
5956 // determines the multiplier: one or three.
5957 static double kPiDividedBy4 = 0.78539816339744830962;
5958 int multiplier = (x < 0) ? -1 : 1;
5959 if (y < 0) multiplier *= 3;
5960 result = multiplier * kPiDividedBy4;
5961 } else {
5962 result = atan2(x, y);
5963 }
5964 return Heap::AllocateHeapNumber(result);
5965}
5966
5967
lrn@chromium.org303ada72010-10-27 09:33:13 +00005968static MaybeObject* Runtime_Math_ceil(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005969 NoHandleAllocation ha;
5970 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005971 Counters::math_ceil.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005972
5973 CONVERT_DOUBLE_CHECKED(x, args[0]);
5974 return Heap::NumberFromDouble(ceiling(x));
5975}
5976
5977
lrn@chromium.org303ada72010-10-27 09:33:13 +00005978static MaybeObject* Runtime_Math_cos(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005979 NoHandleAllocation ha;
5980 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005981 Counters::math_cos.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005982
5983 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005984 return TranscendentalCache::Get(TranscendentalCache::COS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005985}
5986
5987
lrn@chromium.org303ada72010-10-27 09:33:13 +00005988static MaybeObject* Runtime_Math_exp(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005989 NoHandleAllocation ha;
5990 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005991 Counters::math_exp.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005992
5993 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005994 return TranscendentalCache::Get(TranscendentalCache::EXP, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005995}
5996
5997
lrn@chromium.org303ada72010-10-27 09:33:13 +00005998static MaybeObject* Runtime_Math_floor(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005999 NoHandleAllocation ha;
6000 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006001 Counters::math_floor.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006002
6003 CONVERT_DOUBLE_CHECKED(x, args[0]);
6004 return Heap::NumberFromDouble(floor(x));
6005}
6006
6007
lrn@chromium.org303ada72010-10-27 09:33:13 +00006008static MaybeObject* Runtime_Math_log(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006009 NoHandleAllocation ha;
6010 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006011 Counters::math_log.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006012
6013 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006014 return TranscendentalCache::Get(TranscendentalCache::LOG, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006015}
6016
6017
lrn@chromium.org303ada72010-10-27 09:33:13 +00006018static MaybeObject* Runtime_Math_pow(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006019 NoHandleAllocation ha;
6020 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006021 Counters::math_pow.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006022
6023 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006024
6025 // If the second argument is a smi, it is much faster to call the
6026 // custom powi() function than the generic pow().
6027 if (args[1]->IsSmi()) {
6028 int y = Smi::cast(args[1])->value();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006029 return Heap::NumberFromDouble(power_double_int(x, y));
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006030 }
6031
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006032 CONVERT_DOUBLE_CHECKED(y, args[1]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006033 return Heap::AllocateHeapNumber(power_double_double(x, y));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006034}
6035
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006036// Fast version of Math.pow if we know that y is not an integer and
6037// y is not -0.5 or 0.5. Used as slowcase from codegen.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006038static MaybeObject* Runtime_Math_pow_cfunction(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006039 NoHandleAllocation ha;
6040 ASSERT(args.length() == 2);
6041 CONVERT_DOUBLE_CHECKED(x, args[0]);
6042 CONVERT_DOUBLE_CHECKED(y, args[1]);
6043 if (y == 0) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006044 return Smi::FromInt(1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006045 } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006046 return Heap::nan_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006047 } else {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006048 return Heap::AllocateHeapNumber(pow(x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006049 }
6050}
6051
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006052
lrn@chromium.org303ada72010-10-27 09:33:13 +00006053static MaybeObject* Runtime_RoundNumber(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006054 NoHandleAllocation ha;
6055 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006056 Counters::math_round.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006057
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006058 if (!args[0]->IsHeapNumber()) {
6059 // Must be smi. Return the argument unchanged for all the other types
6060 // to make fuzz-natives test happy.
6061 return args[0];
6062 }
6063
6064 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
6065
6066 double value = number->value();
6067 int exponent = number->get_exponent();
6068 int sign = number->get_sign();
6069
6070 // We compare with kSmiValueSize - 3 because (2^30 - 0.1) has exponent 29 and
6071 // should be rounded to 2^30, which is not smi.
6072 if (!sign && exponent <= kSmiValueSize - 3) {
6073 return Smi::FromInt(static_cast<int>(value + 0.5));
6074 }
6075
6076 // If the magnitude is big enough, there's no place for fraction part. If we
6077 // try to add 0.5 to this number, 1.0 will be added instead.
6078 if (exponent >= 52) {
6079 return number;
6080 }
6081
6082 if (sign && value >= -0.5) return Heap::minus_zero_value();
6083
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006084 // Do not call NumberFromDouble() to avoid extra checks.
6085 return Heap::AllocateHeapNumber(floor(value + 0.5));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006086}
6087
6088
lrn@chromium.org303ada72010-10-27 09:33:13 +00006089static MaybeObject* Runtime_Math_sin(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006090 NoHandleAllocation ha;
6091 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006092 Counters::math_sin.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006093
6094 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006095 return TranscendentalCache::Get(TranscendentalCache::SIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006096}
6097
6098
lrn@chromium.org303ada72010-10-27 09:33:13 +00006099static MaybeObject* Runtime_Math_sqrt(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006100 NoHandleAllocation ha;
6101 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006102 Counters::math_sqrt.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006103
6104 CONVERT_DOUBLE_CHECKED(x, args[0]);
6105 return Heap::AllocateHeapNumber(sqrt(x));
6106}
6107
6108
lrn@chromium.org303ada72010-10-27 09:33:13 +00006109static MaybeObject* Runtime_Math_tan(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006110 NoHandleAllocation ha;
6111 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006112 Counters::math_tan.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006113
6114 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006115 return TranscendentalCache::Get(TranscendentalCache::TAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006116}
6117
6118
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006119static int MakeDay(int year, int month, int day) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006120 static const int day_from_month[] = {0, 31, 59, 90, 120, 151,
6121 181, 212, 243, 273, 304, 334};
6122 static const int day_from_month_leap[] = {0, 31, 60, 91, 121, 152,
6123 182, 213, 244, 274, 305, 335};
6124
6125 year += month / 12;
6126 month %= 12;
6127 if (month < 0) {
6128 year--;
6129 month += 12;
6130 }
6131
6132 ASSERT(month >= 0);
6133 ASSERT(month < 12);
6134
6135 // year_delta is an arbitrary number such that:
6136 // a) year_delta = -1 (mod 400)
6137 // b) year + year_delta > 0 for years in the range defined by
6138 // ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of
6139 // Jan 1 1970. This is required so that we don't run into integer
6140 // division of negative numbers.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006141 // c) there shouldn't be an overflow for 32-bit integers in the following
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006142 // operations.
6143 static const int year_delta = 399999;
6144 static const int base_day = 365 * (1970 + year_delta) +
6145 (1970 + year_delta) / 4 -
6146 (1970 + year_delta) / 100 +
6147 (1970 + year_delta) / 400;
6148
6149 int year1 = year + year_delta;
6150 int day_from_year = 365 * year1 +
6151 year1 / 4 -
6152 year1 / 100 +
6153 year1 / 400 -
6154 base_day;
6155
6156 if (year % 4 || (year % 100 == 0 && year % 400 != 0)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006157 return day_from_year + day_from_month[month] + day - 1;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006158 }
6159
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006160 return day_from_year + day_from_month_leap[month] + day - 1;
6161}
6162
6163
lrn@chromium.org303ada72010-10-27 09:33:13 +00006164static MaybeObject* Runtime_DateMakeDay(Arguments args) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006165 NoHandleAllocation ha;
6166 ASSERT(args.length() == 3);
6167
6168 CONVERT_SMI_CHECKED(year, args[0]);
6169 CONVERT_SMI_CHECKED(month, args[1]);
6170 CONVERT_SMI_CHECKED(date, args[2]);
6171
6172 return Smi::FromInt(MakeDay(year, month, date));
6173}
6174
6175
6176static const int kDays4Years[] = {0, 365, 2 * 365, 3 * 365 + 1};
6177static const int kDaysIn4Years = 4 * 365 + 1;
6178static const int kDaysIn100Years = 25 * kDaysIn4Years - 1;
6179static const int kDaysIn400Years = 4 * kDaysIn100Years + 1;
6180static const int kDays1970to2000 = 30 * 365 + 7;
6181static const int kDaysOffset = 1000 * kDaysIn400Years + 5 * kDaysIn400Years -
6182 kDays1970to2000;
6183static const int kYearsOffset = 400000;
6184
6185static const char kDayInYear[] = {
6186 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6187 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6188 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6189 22, 23, 24, 25, 26, 27, 28,
6190 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6191 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6192 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6193 22, 23, 24, 25, 26, 27, 28, 29, 30,
6194 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6195 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6196 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6197 22, 23, 24, 25, 26, 27, 28, 29, 30,
6198 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6199 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6200 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6201 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6202 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6203 22, 23, 24, 25, 26, 27, 28, 29, 30,
6204 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6205 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6206 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6207 22, 23, 24, 25, 26, 27, 28, 29, 30,
6208 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6209 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6210
6211 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6212 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6213 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6214 22, 23, 24, 25, 26, 27, 28,
6215 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6216 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6217 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6218 22, 23, 24, 25, 26, 27, 28, 29, 30,
6219 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6220 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6221 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6222 22, 23, 24, 25, 26, 27, 28, 29, 30,
6223 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6224 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6225 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6226 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6227 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6228 22, 23, 24, 25, 26, 27, 28, 29, 30,
6229 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6230 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6231 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6232 22, 23, 24, 25, 26, 27, 28, 29, 30,
6233 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6234 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6235
6236 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6237 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6238 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6239 22, 23, 24, 25, 26, 27, 28, 29,
6240 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6241 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6242 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6243 22, 23, 24, 25, 26, 27, 28, 29, 30,
6244 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6245 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6246 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6247 22, 23, 24, 25, 26, 27, 28, 29, 30,
6248 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6249 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6250 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6251 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6252 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6253 22, 23, 24, 25, 26, 27, 28, 29, 30,
6254 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6255 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6256 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6257 22, 23, 24, 25, 26, 27, 28, 29, 30,
6258 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6259 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6260
6261 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6262 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6263 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6264 22, 23, 24, 25, 26, 27, 28,
6265 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6266 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6267 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6268 22, 23, 24, 25, 26, 27, 28, 29, 30,
6269 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6270 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6271 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6272 22, 23, 24, 25, 26, 27, 28, 29, 30,
6273 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6274 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6275 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6276 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6277 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6278 22, 23, 24, 25, 26, 27, 28, 29, 30,
6279 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6280 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6281 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6282 22, 23, 24, 25, 26, 27, 28, 29, 30,
6283 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6284 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
6285
6286static const char kMonthInYear[] = {
6287 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,
6288 0, 0, 0, 0, 0, 0,
6289 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,
6290 1, 1, 1,
6291 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,
6292 2, 2, 2, 2, 2, 2,
6293 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,
6294 3, 3, 3, 3, 3,
6295 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,
6296 4, 4, 4, 4, 4, 4,
6297 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,
6298 5, 5, 5, 5, 5,
6299 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,
6300 6, 6, 6, 6, 6, 6,
6301 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,
6302 7, 7, 7, 7, 7, 7,
6303 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,
6304 8, 8, 8, 8, 8,
6305 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,
6306 9, 9, 9, 9, 9, 9,
6307 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6308 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6309 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6310 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6311
6312 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,
6313 0, 0, 0, 0, 0, 0,
6314 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,
6315 1, 1, 1,
6316 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,
6317 2, 2, 2, 2, 2, 2,
6318 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,
6319 3, 3, 3, 3, 3,
6320 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,
6321 4, 4, 4, 4, 4, 4,
6322 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,
6323 5, 5, 5, 5, 5,
6324 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,
6325 6, 6, 6, 6, 6, 6,
6326 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,
6327 7, 7, 7, 7, 7, 7,
6328 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,
6329 8, 8, 8, 8, 8,
6330 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,
6331 9, 9, 9, 9, 9, 9,
6332 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6333 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6334 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6335 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6336
6337 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,
6338 0, 0, 0, 0, 0, 0,
6339 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,
6340 1, 1, 1, 1,
6341 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,
6342 2, 2, 2, 2, 2, 2,
6343 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,
6344 3, 3, 3, 3, 3,
6345 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,
6346 4, 4, 4, 4, 4, 4,
6347 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,
6348 5, 5, 5, 5, 5,
6349 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,
6350 6, 6, 6, 6, 6, 6,
6351 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,
6352 7, 7, 7, 7, 7, 7,
6353 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,
6354 8, 8, 8, 8, 8,
6355 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,
6356 9, 9, 9, 9, 9, 9,
6357 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6358 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6359 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6360 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6361
6362 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,
6363 0, 0, 0, 0, 0, 0,
6364 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,
6365 1, 1, 1,
6366 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,
6367 2, 2, 2, 2, 2, 2,
6368 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,
6369 3, 3, 3, 3, 3,
6370 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,
6371 4, 4, 4, 4, 4, 4,
6372 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,
6373 5, 5, 5, 5, 5,
6374 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,
6375 6, 6, 6, 6, 6, 6,
6376 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,
6377 7, 7, 7, 7, 7, 7,
6378 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,
6379 8, 8, 8, 8, 8,
6380 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,
6381 9, 9, 9, 9, 9, 9,
6382 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6383 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6384 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6385 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11};
6386
6387
6388// This function works for dates from 1970 to 2099.
6389static inline void DateYMDFromTimeAfter1970(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006390 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006391#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00006392 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006393#endif
6394
6395 year = 1970 + (4 * date + 2) / kDaysIn4Years;
6396 date %= kDaysIn4Years;
6397
6398 month = kMonthInYear[date];
6399 day = kDayInYear[date];
6400
6401 ASSERT(MakeDay(year, month, day) == save_date);
6402}
6403
6404
6405static inline void DateYMDFromTimeSlow(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006406 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006407#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00006408 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006409#endif
6410
6411 date += kDaysOffset;
6412 year = 400 * (date / kDaysIn400Years) - kYearsOffset;
6413 date %= kDaysIn400Years;
6414
6415 ASSERT(MakeDay(year, 0, 1) + date == save_date);
6416
6417 date--;
6418 int yd1 = date / kDaysIn100Years;
6419 date %= kDaysIn100Years;
6420 year += 100 * yd1;
6421
6422 date++;
6423 int yd2 = date / kDaysIn4Years;
6424 date %= kDaysIn4Years;
6425 year += 4 * yd2;
6426
6427 date--;
6428 int yd3 = date / 365;
6429 date %= 365;
6430 year += yd3;
6431
6432 bool is_leap = (!yd1 || yd2) && !yd3;
6433
6434 ASSERT(date >= -1);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006435 ASSERT(is_leap || (date >= 0));
6436 ASSERT((date < 365) || (is_leap && (date < 366)));
6437 ASSERT(is_leap == ((year % 4 == 0) && (year % 100 || (year % 400 == 0))));
6438 ASSERT(is_leap || ((MakeDay(year, 0, 1) + date) == save_date));
6439 ASSERT(!is_leap || ((MakeDay(year, 0, 1) + date + 1) == save_date));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006440
6441 if (is_leap) {
6442 day = kDayInYear[2*365 + 1 + date];
6443 month = kMonthInYear[2*365 + 1 + date];
6444 } else {
6445 day = kDayInYear[date];
6446 month = kMonthInYear[date];
6447 }
6448
6449 ASSERT(MakeDay(year, month, day) == save_date);
6450}
6451
6452
6453static inline void DateYMDFromTime(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006454 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006455 if (date >= 0 && date < 32 * kDaysIn4Years) {
6456 DateYMDFromTimeAfter1970(date, year, month, day);
6457 } else {
6458 DateYMDFromTimeSlow(date, year, month, day);
6459 }
6460}
6461
6462
lrn@chromium.org303ada72010-10-27 09:33:13 +00006463static MaybeObject* Runtime_DateYMDFromTime(Arguments args) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006464 NoHandleAllocation ha;
6465 ASSERT(args.length() == 2);
6466
6467 CONVERT_DOUBLE_CHECKED(t, args[0]);
6468 CONVERT_CHECKED(JSArray, res_array, args[1]);
6469
6470 int year, month, day;
6471 DateYMDFromTime(static_cast<int>(floor(t / 86400000)), year, month, day);
6472
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00006473 RUNTIME_ASSERT(res_array->elements()->map() == Heap::fixed_array_map());
6474 FixedArray* elms = FixedArray::cast(res_array->elements());
6475 RUNTIME_ASSERT(elms->length() == 3);
6476
6477 elms->set(0, Smi::FromInt(year));
6478 elms->set(1, Smi::FromInt(month));
6479 elms->set(2, Smi::FromInt(day));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006480
6481 return Heap::undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006482}
6483
6484
lrn@chromium.org303ada72010-10-27 09:33:13 +00006485static MaybeObject* Runtime_NewArgumentsFast(Arguments args) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00006486 NoHandleAllocation ha;
6487 ASSERT(args.length() == 3);
6488
6489 JSFunction* callee = JSFunction::cast(args[0]);
6490 Object** parameters = reinterpret_cast<Object**>(args[1]);
6491 const int length = Smi::cast(args[2])->value();
6492
lrn@chromium.org303ada72010-10-27 09:33:13 +00006493 Object* result;
6494 { MaybeObject* maybe_result = Heap::AllocateArgumentsObject(callee, length);
6495 if (!maybe_result->ToObject(&result)) return maybe_result;
6496 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006497 // Allocate the elements if needed.
6498 if (length > 0) {
6499 // Allocate the fixed array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006500 Object* obj;
6501 { MaybeObject* maybe_obj = Heap::AllocateRawFixedArray(length);
6502 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6503 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006504
6505 AssertNoAllocation no_gc;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006506 FixedArray* array = reinterpret_cast<FixedArray*>(obj);
6507 array->set_map(Heap::fixed_array_map());
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006508 array->set_length(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006509
6510 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006511 for (int i = 0; i < length; i++) {
6512 array->set(i, *--parameters, mode);
6513 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006514 JSObject::cast(result)->set_elements(FixedArray::cast(obj));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00006515 }
6516 return result;
6517}
6518
6519
lrn@chromium.org303ada72010-10-27 09:33:13 +00006520static MaybeObject* Runtime_NewClosure(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006521 HandleScope scope;
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00006522 ASSERT(args.length() == 3);
ager@chromium.org3811b432009-10-28 14:53:37 +00006523 CONVERT_ARG_CHECKED(Context, context, 0);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00006524 CONVERT_ARG_CHECKED(SharedFunctionInfo, shared, 1);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00006525 CONVERT_BOOLEAN_CHECKED(pretenure, args[2]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006526
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00006527 // Allocate global closures in old space and allocate local closures
6528 // in new space. Additionally pretenure closures that are assigned
6529 // directly to properties.
6530 pretenure = pretenure || (context->global_context() == *context);
6531 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006532 Handle<JSFunction> result =
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00006533 Factory::NewFunctionFromSharedFunctionInfo(shared,
6534 context,
6535 pretenure_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006536 return *result;
6537}
6538
lrn@chromium.org303ada72010-10-27 09:33:13 +00006539static MaybeObject* Runtime_NewObjectFromBound(Arguments args) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006540 HandleScope scope;
6541 ASSERT(args.length() == 2);
6542 CONVERT_ARG_CHECKED(JSFunction, function, 0);
6543 CONVERT_ARG_CHECKED(JSArray, params, 1);
6544
whesse@chromium.orge90029b2010-08-02 11:52:17 +00006545 RUNTIME_ASSERT(params->HasFastElements());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006546 FixedArray* fixed = FixedArray::cast(params->elements());
6547
whesse@chromium.orge90029b2010-08-02 11:52:17 +00006548 int fixed_length = Smi::cast(params->length())->value();
6549 SmartPointer<Object**> param_data(NewArray<Object**>(fixed_length));
6550 for (int i = 0; i < fixed_length; i++) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006551 Handle<Object> val = Handle<Object>(fixed->get(i));
6552 param_data[i] = val.location();
6553 }
6554
whesse@chromium.orge90029b2010-08-02 11:52:17 +00006555 bool exception = false;
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006556 Handle<Object> result = Execution::New(
whesse@chromium.orge90029b2010-08-02 11:52:17 +00006557 function, fixed_length, *param_data, &exception);
6558 if (exception) {
6559 return Failure::Exception();
6560 }
6561 ASSERT(!result.is_null());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006562 return *result;
6563}
6564
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006565
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006566static void TrySettingInlineConstructStub(Handle<JSFunction> function) {
ager@chromium.org5c838252010-02-19 08:53:10 +00006567 Handle<Object> prototype = Factory::null_value();
6568 if (function->has_instance_prototype()) {
6569 prototype = Handle<Object>(function->instance_prototype());
6570 }
6571 if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006572 ConstructStubCompiler compiler;
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006573 MaybeObject* code = compiler.CompileConstructStub(*function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006574 if (!code->IsFailure()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00006575 function->shared()->set_construct_stub(
6576 Code::cast(code->ToObjectUnchecked()));
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006577 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006578 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006579}
6580
6581
lrn@chromium.org303ada72010-10-27 09:33:13 +00006582static MaybeObject* Runtime_NewObject(Arguments args) {
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006583 HandleScope scope;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006584 ASSERT(args.length() == 1);
6585
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006586 Handle<Object> constructor = args.at<Object>(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006587
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006588 // If the constructor isn't a proper function we throw a type error.
6589 if (!constructor->IsJSFunction()) {
6590 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
6591 Handle<Object> type_error =
6592 Factory::NewTypeError("not_constructor", arguments);
6593 return Top::Throw(*type_error);
6594 }
6595
6596 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006597
6598 // If function should not have prototype, construction is not allowed. In this
6599 // case generated code bailouts here, since function has no initial_map.
6600 if (!function->should_have_prototype()) {
6601 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
6602 Handle<Object> type_error =
6603 Factory::NewTypeError("not_constructor", arguments);
6604 return Top::Throw(*type_error);
6605 }
6606
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006607#ifdef ENABLE_DEBUGGER_SUPPORT
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006608 // Handle stepping into constructors if step into is active.
6609 if (Debug::StepInActive()) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006610 Debug::HandleStepIn(function, Handle<Object>::null(), 0, true);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006611 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006612#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006613
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006614 if (function->has_initial_map()) {
6615 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006616 // The 'Function' function ignores the receiver object when
6617 // called using 'new' and creates a new JSFunction object that
6618 // is returned. The receiver object is only used for error
6619 // reporting if an error occurs when constructing the new
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006620 // JSFunction. Factory::NewJSObject() should not be used to
6621 // allocate JSFunctions since it does not properly initialize
6622 // the shared part of the function. Since the receiver is
6623 // ignored anyway, we use the global object as the receiver
6624 // instead of a new JSFunction object. This way, errors are
6625 // reported the same way whether or not 'Function' is called
6626 // using 'new'.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006627 return Top::context()->global();
6628 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006629 }
6630
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006631 // The function should be compiled for the optimization hints to be
6632 // available. We cannot use EnsureCompiled because that forces a
6633 // compilation through the shared function info which makes it
6634 // impossible for us to optimize.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006635 Handle<SharedFunctionInfo> shared(function->shared());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006636 if (!function->is_compiled()) CompileLazy(function, CLEAR_EXCEPTION);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006637
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006638 if (!function->has_initial_map() &&
6639 shared->IsInobjectSlackTrackingInProgress()) {
6640 // The tracking is already in progress for another function. We can only
6641 // track one initial_map at a time, so we force the completion before the
6642 // function is called as a constructor for the first time.
6643 shared->CompleteInobjectSlackTracking();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006644 }
6645
6646 bool first_allocation = !shared->live_objects_may_exist();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006647 Handle<JSObject> result = Factory::NewJSObject(function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006648 // Delay setting the stub if inobject slack tracking is in progress.
6649 if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) {
6650 TrySettingInlineConstructStub(function);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006651 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006652
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00006653 Counters::constructed_objects.Increment();
6654 Counters::constructed_objects_runtime.Increment();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006655
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006656 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006657}
6658
6659
lrn@chromium.org303ada72010-10-27 09:33:13 +00006660static MaybeObject* Runtime_FinalizeInstanceSize(Arguments args) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006661 HandleScope scope;
6662 ASSERT(args.length() == 1);
6663
6664 CONVERT_ARG_CHECKED(JSFunction, function, 0);
6665 function->shared()->CompleteInobjectSlackTracking();
6666 TrySettingInlineConstructStub(function);
6667
6668 return Heap::undefined_value();
6669}
6670
6671
lrn@chromium.org303ada72010-10-27 09:33:13 +00006672static MaybeObject* Runtime_LazyCompile(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006673 HandleScope scope;
6674 ASSERT(args.length() == 1);
6675
6676 Handle<JSFunction> function = args.at<JSFunction>(0);
6677#ifdef DEBUG
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00006678 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006679 PrintF("[lazy: ");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006680 function->PrintName();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006681 PrintF("]\n");
6682 }
6683#endif
6684
kasperl@chromium.org71affb52009-05-26 05:44:31 +00006685 // Compile the target function. Here we compile using CompileLazyInLoop in
6686 // order to get the optimized version. This helps code like delta-blue
6687 // that calls performance-critical routines through constructors. A
6688 // constructor call doesn't use a CallIC, it uses a LoadIC followed by a
6689 // direct call. Since the in-loop tracking takes place through CallICs
6690 // this means that things called through constructors are never known to
6691 // be in loops. We compile them as if they are in loops here just in case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006692 ASSERT(!function->is_compiled());
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00006693 if (!CompileLazyInLoop(function, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006694 return Failure::Exception();
6695 }
6696
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006697 // All done. Return the compiled code.
6698 ASSERT(function->is_compiled());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006699 return function->code();
6700}
6701
6702
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006703static MaybeObject* Runtime_LazyRecompile(Arguments args) {
6704 HandleScope scope;
6705 ASSERT(args.length() == 1);
6706 Handle<JSFunction> function = args.at<JSFunction>(0);
6707 // If the function is not optimizable or debugger is active continue using the
6708 // code from the full compiler.
6709 if (!function->shared()->code()->optimizable() ||
6710 Debug::has_break_points()) {
6711 function->ReplaceCode(function->shared()->code());
6712 return function->code();
6713 }
6714 if (CompileOptimized(function, AstNode::kNoNumber)) {
6715 return function->code();
6716 }
6717 function->ReplaceCode(function->shared()->code());
6718 return Failure::Exception();
6719}
6720
6721
6722static MaybeObject* Runtime_NotifyDeoptimized(Arguments args) {
6723 HandleScope scope;
6724 ASSERT(args.length() == 1);
6725 RUNTIME_ASSERT(args[0]->IsSmi());
6726 Deoptimizer::BailoutType type =
6727 static_cast<Deoptimizer::BailoutType>(Smi::cast(args[0])->value());
6728 Deoptimizer* deoptimizer = Deoptimizer::Grab();
6729 ASSERT(Heap::IsAllocationAllowed());
6730 int frames = deoptimizer->output_count();
6731
6732 JavaScriptFrameIterator it;
6733 JavaScriptFrame* frame = NULL;
6734 for (int i = 0; i < frames; i++) {
6735 if (i != 0) it.Advance();
6736 frame = it.frame();
6737 deoptimizer->InsertHeapNumberValues(frames - i - 1, frame);
6738 }
6739 delete deoptimizer;
6740
6741 RUNTIME_ASSERT(frame->function()->IsJSFunction());
6742 Handle<JSFunction> function(JSFunction::cast(frame->function()));
6743 Handle<Object> arguments;
6744 for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
6745 if (frame->GetExpression(i) == Heap::the_hole_value()) {
6746 if (arguments.is_null()) {
6747 // FunctionGetArguments can't throw an exception, so cast away the
6748 // doubt with an assert.
6749 arguments = Handle<Object>(
6750 Accessors::FunctionGetArguments(*function,
6751 NULL)->ToObjectUnchecked());
6752 ASSERT(*arguments != Heap::null_value());
6753 ASSERT(*arguments != Heap::undefined_value());
6754 }
6755 frame->SetExpression(i, *arguments);
6756 }
6757 }
6758
6759 CompilationCache::MarkForLazyOptimizing(function);
6760 if (type == Deoptimizer::EAGER) {
6761 RUNTIME_ASSERT(function->IsOptimized());
6762 } else {
6763 RUNTIME_ASSERT(!function->IsOptimized());
6764 }
6765
6766 // Avoid doing too much work when running with --always-opt and keep
6767 // the optimized code around.
6768 if (FLAG_always_opt || type == Deoptimizer::LAZY) {
6769 return Heap::undefined_value();
6770 }
6771
6772 // Count the number of optimized activations of the function.
6773 int activations = 0;
6774 while (!it.done()) {
6775 JavaScriptFrame* frame = it.frame();
6776 if (frame->is_optimized() && frame->function() == *function) {
6777 activations++;
6778 }
6779 it.Advance();
6780 }
6781
6782 // TODO(kasperl): For now, we cannot support removing the optimized
6783 // code when we have recursive invocations of the same function.
6784 if (activations == 0) {
6785 if (FLAG_trace_deopt) {
6786 PrintF("[removing optimized code for: ");
6787 function->PrintName();
6788 PrintF("]\n");
6789 }
6790 function->ReplaceCode(function->shared()->code());
6791 }
6792 return Heap::undefined_value();
6793}
6794
6795
6796static MaybeObject* Runtime_NotifyOSR(Arguments args) {
6797 Deoptimizer* deoptimizer = Deoptimizer::Grab();
6798 delete deoptimizer;
6799 return Heap::undefined_value();
6800}
6801
6802
6803static MaybeObject* Runtime_DeoptimizeFunction(Arguments args) {
6804 HandleScope scope;
6805 ASSERT(args.length() == 1);
6806 CONVERT_ARG_CHECKED(JSFunction, function, 0);
6807 if (!function->IsOptimized()) return Heap::undefined_value();
6808
6809 Deoptimizer::DeoptimizeFunction(*function);
6810
6811 return Heap::undefined_value();
6812}
6813
6814
6815static MaybeObject* Runtime_CompileForOnStackReplacement(Arguments args) {
6816 HandleScope scope;
6817 ASSERT(args.length() == 1);
6818 CONVERT_ARG_CHECKED(JSFunction, function, 0);
6819
6820 // We're not prepared to handle a function with arguments object.
6821 ASSERT(!function->shared()->scope_info()->HasArgumentsShadow());
6822
6823 // We have hit a back edge in an unoptimized frame for a function that was
6824 // selected for on-stack replacement. Find the unoptimized code object.
6825 Handle<Code> unoptimized(function->shared()->code());
6826 // Keep track of whether we've succeeded in optimizing.
6827 bool succeeded = unoptimized->optimizable();
6828 if (succeeded) {
6829 // If we are trying to do OSR when there are already optimized
6830 // activations of the function, it means (a) the function is directly or
6831 // indirectly recursive and (b) an optimized invocation has been
6832 // deoptimized so that we are currently in an unoptimized activation.
6833 // Check for optimized activations of this function.
6834 JavaScriptFrameIterator it;
6835 while (succeeded && !it.done()) {
6836 JavaScriptFrame* frame = it.frame();
6837 succeeded = !frame->is_optimized() || frame->function() != *function;
6838 it.Advance();
6839 }
6840 }
6841
6842 int ast_id = AstNode::kNoNumber;
6843 if (succeeded) {
6844 // The top JS function is this one, the PC is somewhere in the
6845 // unoptimized code.
6846 JavaScriptFrameIterator it;
6847 JavaScriptFrame* frame = it.frame();
6848 ASSERT(frame->function() == *function);
6849 ASSERT(frame->code() == *unoptimized);
6850 ASSERT(unoptimized->contains(frame->pc()));
6851
6852 // Use linear search of the unoptimized code's stack check table to find
6853 // the AST id matching the PC.
6854 Address start = unoptimized->instruction_start();
6855 unsigned target_pc_offset = static_cast<unsigned>(frame->pc() - start);
6856 Address table_cursor = start + unoptimized->stack_check_table_start();
6857 uint32_t table_length = Memory::uint32_at(table_cursor);
6858 table_cursor += kIntSize;
6859 for (unsigned i = 0; i < table_length; ++i) {
6860 // Table entries are (AST id, pc offset) pairs.
6861 uint32_t pc_offset = Memory::uint32_at(table_cursor + kIntSize);
6862 if (pc_offset == target_pc_offset) {
6863 ast_id = static_cast<int>(Memory::uint32_at(table_cursor));
6864 break;
6865 }
6866 table_cursor += 2 * kIntSize;
6867 }
6868 ASSERT(ast_id != AstNode::kNoNumber);
6869 if (FLAG_trace_osr) {
6870 PrintF("[replacing on-stack at AST id %d in ", ast_id);
6871 function->PrintName();
6872 PrintF("]\n");
6873 }
6874
6875 // Try to compile the optimized code. A true return value from
6876 // CompileOptimized means that compilation succeeded, not necessarily
6877 // that optimization succeeded.
6878 if (CompileOptimized(function, ast_id) && function->IsOptimized()) {
6879 DeoptimizationInputData* data = DeoptimizationInputData::cast(
6880 function->code()->deoptimization_data());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006881 if (data->OsrPcOffset()->value() >= 0) {
6882 if (FLAG_trace_osr) {
6883 PrintF("[on-stack replacement offset %d in optimized code]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006884 data->OsrPcOffset()->value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006885 }
6886 ASSERT(data->OsrAstId()->value() == ast_id);
6887 } else {
6888 // We may never generate the desired OSR entry if we emit an
6889 // early deoptimize.
6890 succeeded = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006891 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006892 } else {
6893 succeeded = false;
6894 }
6895 }
6896
6897 // Revert to the original stack checks in the original unoptimized code.
6898 if (FLAG_trace_osr) {
6899 PrintF("[restoring original stack checks in ");
6900 function->PrintName();
6901 PrintF("]\n");
6902 }
6903 StackCheckStub check_stub;
6904 Handle<Code> check_code = check_stub.GetCode();
6905 Handle<Code> replacement_code(
6906 Builtins::builtin(Builtins::OnStackReplacement));
6907 // Iterate the unoptimized code and revert all the patched stack checks.
6908 for (RelocIterator it(*unoptimized, RelocInfo::kCodeTargetMask);
6909 !it.done();
6910 it.next()) {
6911 RelocInfo* rinfo = it.rinfo();
6912 if (rinfo->target_address() == replacement_code->entry()) {
6913 Deoptimizer::RevertStackCheckCode(rinfo, *check_code);
6914 }
6915 }
6916
6917 // Allow OSR only at nesting level zero again.
6918 unoptimized->set_allow_osr_at_loop_nesting_level(0);
6919
6920 // If the optimization attempt succeeded, return the AST id tagged as a
6921 // smi. This tells the builtin that we need to translate the unoptimized
6922 // frame to an optimized one.
6923 if (succeeded) {
6924 ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
6925 return Smi::FromInt(ast_id);
6926 } else {
6927 return Smi::FromInt(-1);
6928 }
6929}
6930
6931
lrn@chromium.org303ada72010-10-27 09:33:13 +00006932static MaybeObject* Runtime_GetFunctionDelegate(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006933 HandleScope scope;
6934 ASSERT(args.length() == 1);
6935 RUNTIME_ASSERT(!args[0]->IsJSFunction());
6936 return *Execution::GetFunctionDelegate(args.at<Object>(0));
6937}
6938
6939
lrn@chromium.org303ada72010-10-27 09:33:13 +00006940static MaybeObject* Runtime_GetConstructorDelegate(Arguments args) {
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00006941 HandleScope scope;
6942 ASSERT(args.length() == 1);
6943 RUNTIME_ASSERT(!args[0]->IsJSFunction());
6944 return *Execution::GetConstructorDelegate(args.at<Object>(0));
6945}
6946
6947
lrn@chromium.org303ada72010-10-27 09:33:13 +00006948static MaybeObject* Runtime_NewContext(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006949 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00006950 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006951
kasper.lund7276f142008-07-30 08:49:36 +00006952 CONVERT_CHECKED(JSFunction, function, args[0]);
ager@chromium.orgb5737492010-07-15 09:29:43 +00006953 int length = function->shared()->scope_info()->NumberOfContextSlots();
lrn@chromium.org303ada72010-10-27 09:33:13 +00006954 Object* result;
6955 { MaybeObject* maybe_result = Heap::AllocateFunctionContext(length, function);
6956 if (!maybe_result->ToObject(&result)) return maybe_result;
6957 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006958
6959 Top::set_context(Context::cast(result));
6960
kasper.lund7276f142008-07-30 08:49:36 +00006961 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006962}
6963
lrn@chromium.org303ada72010-10-27 09:33:13 +00006964
6965MUST_USE_RESULT static MaybeObject* PushContextHelper(Object* object,
6966 bool is_catch_context) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006967 // Convert the object to a proper JavaScript object.
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00006968 Object* js_object = object;
6969 if (!js_object->IsJSObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00006970 MaybeObject* maybe_js_object = js_object->ToObject();
6971 if (!maybe_js_object->ToObject(&js_object)) {
6972 if (!Failure::cast(maybe_js_object)->IsInternalError()) {
6973 return maybe_js_object;
6974 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006975 HandleScope scope;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00006976 Handle<Object> handle(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006977 Handle<Object> result =
6978 Factory::NewTypeError("with_expression", HandleVector(&handle, 1));
6979 return Top::Throw(*result);
6980 }
6981 }
6982
lrn@chromium.org303ada72010-10-27 09:33:13 +00006983 Object* result;
6984 { MaybeObject* maybe_result =
6985 Heap::AllocateWithContext(Top::context(),
6986 JSObject::cast(js_object),
6987 is_catch_context);
6988 if (!maybe_result->ToObject(&result)) return maybe_result;
6989 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006990
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00006991 Context* context = Context::cast(result);
6992 Top::set_context(context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006993
kasper.lund7276f142008-07-30 08:49:36 +00006994 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006995}
6996
6997
lrn@chromium.org303ada72010-10-27 09:33:13 +00006998static MaybeObject* Runtime_PushContext(Arguments args) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00006999 NoHandleAllocation ha;
7000 ASSERT(args.length() == 1);
7001 return PushContextHelper(args[0], false);
7002}
7003
7004
lrn@chromium.org303ada72010-10-27 09:33:13 +00007005static MaybeObject* Runtime_PushCatchContext(Arguments args) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007006 NoHandleAllocation ha;
7007 ASSERT(args.length() == 1);
7008 return PushContextHelper(args[0], true);
7009}
7010
7011
lrn@chromium.org303ada72010-10-27 09:33:13 +00007012static MaybeObject* Runtime_LookupContext(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007013 HandleScope scope;
7014 ASSERT(args.length() == 2);
7015
7016 CONVERT_ARG_CHECKED(Context, context, 0);
7017 CONVERT_ARG_CHECKED(String, name, 1);
7018
7019 int index;
7020 PropertyAttributes attributes;
7021 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007022 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007023 context->Lookup(name, flags, &index, &attributes);
7024
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007025 if (index < 0 && !holder.is_null()) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007026 ASSERT(holder->IsJSObject());
7027 return *holder;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007028 }
7029
7030 // No intermediate context found. Use global object by default.
7031 return Top::context()->global();
7032}
7033
7034
ager@chromium.orga1645e22009-09-09 19:27:10 +00007035// A mechanism to return a pair of Object pointers in registers (if possible).
7036// How this is achieved is calling convention-dependent.
7037// All currently supported x86 compiles uses calling conventions that are cdecl
7038// variants where a 64-bit value is returned in two 32-bit registers
7039// (edx:eax on ia32, r1:r0 on ARM).
7040// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
7041// In Win64 calling convention, a struct of two pointers is returned in memory,
7042// allocated by the caller, and passed as a pointer in a hidden first parameter.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007043#ifdef V8_HOST_ARCH_64_BIT
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007044struct ObjectPair {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007045 MaybeObject* x;
7046 MaybeObject* y;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007047};
ager@chromium.orga1645e22009-09-09 19:27:10 +00007048
lrn@chromium.org303ada72010-10-27 09:33:13 +00007049static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007050 ObjectPair result = {x, y};
ager@chromium.orga1645e22009-09-09 19:27:10 +00007051 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
7052 // In Win64 they are assigned to a hidden first argument.
7053 return result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007054}
7055#else
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007056typedef uint64_t ObjectPair;
lrn@chromium.org303ada72010-10-27 09:33:13 +00007057static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007058 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007059 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007060}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007061#endif
7062
7063
lrn@chromium.org303ada72010-10-27 09:33:13 +00007064static inline MaybeObject* Unhole(MaybeObject* x,
7065 PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007066 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
7067 USE(attributes);
7068 return x->IsTheHole() ? Heap::undefined_value() : x;
7069}
7070
7071
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007072static JSObject* ComputeReceiverForNonGlobal(JSObject* holder) {
7073 ASSERT(!holder->IsGlobalObject());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007074 Context* top = Top::context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007075 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007076 JSFunction* context_extension_function =
7077 top->global_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007078 // If the holder isn't a context extension object, we just return it
7079 // as the receiver. This allows arguments objects to be used as
7080 // receivers, but only if they are put in the context scope chain
7081 // explicitly via a with-statement.
7082 Object* constructor = holder->map()->constructor();
7083 if (constructor != context_extension_function) return holder;
7084 // Fall back to using the global object as the receiver if the
7085 // property turns out to be a local variable allocated in a context
7086 // extension object - introduced via eval.
7087 return top->global()->global_receiver();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007088}
7089
7090
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007091static ObjectPair LoadContextSlotHelper(Arguments args, bool throw_error) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007092 HandleScope scope;
ager@chromium.orga1645e22009-09-09 19:27:10 +00007093 ASSERT_EQ(2, args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007094
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007095 if (!args[0]->IsContext() || !args[1]->IsString()) {
ager@chromium.org3e875802009-06-29 08:26:34 +00007096 return MakePair(Top::ThrowIllegalOperation(), NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007097 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007098 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007099 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007100
7101 int index;
7102 PropertyAttributes attributes;
7103 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007104 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007105 context->Lookup(name, flags, &index, &attributes);
7106
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007107 // If the index is non-negative, the slot has been found in a local
7108 // variable or a parameter. Read it from the context object or the
7109 // arguments object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007110 if (index >= 0) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007111 // If the "property" we were looking for is a local variable or an
7112 // argument in a context, the receiver is the global object; see
7113 // ECMA-262, 3rd., 10.1.6 and 10.2.3.
7114 JSObject* receiver = Top::context()->global()->global_receiver();
lrn@chromium.org303ada72010-10-27 09:33:13 +00007115 MaybeObject* value = (holder->IsContext())
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007116 ? Context::cast(*holder)->get(index)
7117 : JSObject::cast(*holder)->GetElement(index);
7118 return MakePair(Unhole(value, attributes), receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007119 }
7120
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007121 // If the holder is found, we read the property from it.
7122 if (!holder.is_null() && holder->IsJSObject()) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007123 ASSERT(Handle<JSObject>::cast(holder)->HasProperty(*name));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007124 JSObject* object = JSObject::cast(*holder);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007125 JSObject* receiver;
7126 if (object->IsGlobalObject()) {
7127 receiver = GlobalObject::cast(object)->global_receiver();
7128 } else if (context->is_exception_holder(*holder)) {
7129 receiver = Top::context()->global()->global_receiver();
7130 } else {
7131 receiver = ComputeReceiverForNonGlobal(object);
7132 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007133 // No need to unhole the value here. This is taken care of by the
7134 // GetProperty function.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007135 MaybeObject* value = object->GetProperty(*name);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007136 return MakePair(value, receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007137 }
7138
7139 if (throw_error) {
7140 // The property doesn't exist - throw exception.
7141 Handle<Object> reference_error =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007142 Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007143 return MakePair(Top::Throw(*reference_error), NULL);
7144 } else {
7145 // The property doesn't exist - return undefined
7146 return MakePair(Heap::undefined_value(), Heap::undefined_value());
7147 }
7148}
7149
7150
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007151static ObjectPair Runtime_LoadContextSlot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007152 return LoadContextSlotHelper(args, true);
7153}
7154
7155
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007156static ObjectPair Runtime_LoadContextSlotNoReferenceError(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007157 return LoadContextSlotHelper(args, false);
7158}
7159
7160
lrn@chromium.org303ada72010-10-27 09:33:13 +00007161static MaybeObject* Runtime_StoreContextSlot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007162 HandleScope scope;
7163 ASSERT(args.length() == 3);
7164
7165 Handle<Object> value(args[0]);
7166 CONVERT_ARG_CHECKED(Context, context, 1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007167 CONVERT_ARG_CHECKED(String, name, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007168
7169 int index;
7170 PropertyAttributes attributes;
7171 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007172 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007173 context->Lookup(name, flags, &index, &attributes);
7174
7175 if (index >= 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007176 if (holder->IsContext()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007177 // Ignore if read_only variable.
7178 if ((attributes & READ_ONLY) == 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007179 Handle<Context>::cast(holder)->set(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007180 }
7181 } else {
7182 ASSERT((attributes & READ_ONLY) == 0);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007183 Handle<JSObject>::cast(holder)->SetElement(index, *value)->
7184 ToObjectUnchecked();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007185 }
7186 return *value;
7187 }
7188
7189 // Slow case: The property is not in a FixedArray context.
7190 // It is either in an JSObject extension context or it was not found.
7191 Handle<JSObject> context_ext;
7192
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007193 if (!holder.is_null()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007194 // The property exists in the extension context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007195 context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007196 } else {
7197 // The property was not found. It needs to be stored in the global context.
7198 ASSERT(attributes == ABSENT);
7199 attributes = NONE;
7200 context_ext = Handle<JSObject>(Top::context()->global());
7201 }
7202
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007203 // Set the property, but ignore if read_only variable on the context
7204 // extension object itself.
7205 if ((attributes & READ_ONLY) == 0 ||
7206 (context_ext->GetLocalPropertyAttribute(*name) == ABSENT)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007207 Handle<Object> set = SetProperty(context_ext, name, value, attributes);
7208 if (set.is_null()) {
7209 // Failure::Exception is converted to a null handle in the
7210 // handle-based methods such as SetProperty. We therefore need
7211 // to convert null handles back to exceptions.
7212 ASSERT(Top::has_pending_exception());
7213 return Failure::Exception();
7214 }
7215 }
7216 return *value;
7217}
7218
7219
lrn@chromium.org303ada72010-10-27 09:33:13 +00007220static MaybeObject* Runtime_Throw(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007221 HandleScope scope;
7222 ASSERT(args.length() == 1);
7223
7224 return Top::Throw(args[0]);
7225}
7226
7227
lrn@chromium.org303ada72010-10-27 09:33:13 +00007228static MaybeObject* Runtime_ReThrow(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007229 HandleScope scope;
7230 ASSERT(args.length() == 1);
7231
7232 return Top::ReThrow(args[0]);
7233}
7234
7235
lrn@chromium.org303ada72010-10-27 09:33:13 +00007236static MaybeObject* Runtime_PromoteScheduledException(Arguments args) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007237 ASSERT_EQ(0, args.length());
7238 return Top::PromoteScheduledException();
7239}
7240
7241
lrn@chromium.org303ada72010-10-27 09:33:13 +00007242static MaybeObject* Runtime_ThrowReferenceError(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007243 HandleScope scope;
7244 ASSERT(args.length() == 1);
7245
7246 Handle<Object> name(args[0]);
7247 Handle<Object> reference_error =
7248 Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
7249 return Top::Throw(*reference_error);
7250}
7251
7252
lrn@chromium.org303ada72010-10-27 09:33:13 +00007253static MaybeObject* Runtime_StackOverflow(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007254 NoHandleAllocation na;
7255 return Top::StackOverflow();
7256}
7257
7258
lrn@chromium.org303ada72010-10-27 09:33:13 +00007259static MaybeObject* Runtime_StackGuard(Arguments args) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00007260 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007261
7262 // First check if this is a real stack overflow.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00007263 if (StackGuard::IsStackOverflow()) {
7264 return Runtime_StackOverflow(args);
7265 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007266
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007267 return Execution::HandleStackGuardInterrupt();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007268}
7269
7270
7271// NOTE: These PrintXXX functions are defined for all builds (not just
7272// DEBUG builds) because we may want to be able to trace function
7273// calls in all modes.
7274static void PrintString(String* str) {
7275 // not uncommon to have empty strings
7276 if (str->length() > 0) {
7277 SmartPointer<char> s =
7278 str->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
7279 PrintF("%s", *s);
7280 }
7281}
7282
7283
7284static void PrintObject(Object* obj) {
7285 if (obj->IsSmi()) {
7286 PrintF("%d", Smi::cast(obj)->value());
7287 } else if (obj->IsString() || obj->IsSymbol()) {
7288 PrintString(String::cast(obj));
7289 } else if (obj->IsNumber()) {
7290 PrintF("%g", obj->Number());
7291 } else if (obj->IsFailure()) {
7292 PrintF("<failure>");
7293 } else if (obj->IsUndefined()) {
7294 PrintF("<undefined>");
7295 } else if (obj->IsNull()) {
7296 PrintF("<null>");
7297 } else if (obj->IsTrue()) {
7298 PrintF("<true>");
7299 } else if (obj->IsFalse()) {
7300 PrintF("<false>");
7301 } else {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007302 PrintF("%p", reinterpret_cast<void*>(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007303 }
7304}
7305
7306
7307static int StackSize() {
7308 int n = 0;
7309 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
7310 return n;
7311}
7312
7313
7314static void PrintTransition(Object* result) {
7315 // indentation
7316 { const int nmax = 80;
7317 int n = StackSize();
7318 if (n <= nmax)
7319 PrintF("%4d:%*s", n, n, "");
7320 else
7321 PrintF("%4d:%*s", n, nmax, "...");
7322 }
7323
7324 if (result == NULL) {
7325 // constructor calls
7326 JavaScriptFrameIterator it;
7327 JavaScriptFrame* frame = it.frame();
7328 if (frame->IsConstructor()) PrintF("new ");
7329 // function name
7330 Object* fun = frame->function();
7331 if (fun->IsJSFunction()) {
7332 PrintObject(JSFunction::cast(fun)->shared()->name());
7333 } else {
7334 PrintObject(fun);
7335 }
7336 // function arguments
7337 // (we are intentionally only printing the actually
7338 // supplied parameters, not all parameters required)
7339 PrintF("(this=");
7340 PrintObject(frame->receiver());
7341 const int length = frame->GetProvidedParametersCount();
7342 for (int i = 0; i < length; i++) {
7343 PrintF(", ");
7344 PrintObject(frame->GetParameter(i));
7345 }
7346 PrintF(") {\n");
7347
7348 } else {
7349 // function result
7350 PrintF("} -> ");
7351 PrintObject(result);
7352 PrintF("\n");
7353 }
7354}
7355
7356
lrn@chromium.org303ada72010-10-27 09:33:13 +00007357static MaybeObject* Runtime_TraceEnter(Arguments args) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007358 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007359 NoHandleAllocation ha;
7360 PrintTransition(NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007361 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007362}
7363
7364
lrn@chromium.org303ada72010-10-27 09:33:13 +00007365static MaybeObject* Runtime_TraceExit(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007366 NoHandleAllocation ha;
7367 PrintTransition(args[0]);
7368 return args[0]; // return TOS
7369}
7370
7371
lrn@chromium.org303ada72010-10-27 09:33:13 +00007372static MaybeObject* Runtime_DebugPrint(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007373 NoHandleAllocation ha;
7374 ASSERT(args.length() == 1);
7375
7376#ifdef DEBUG
7377 if (args[0]->IsString()) {
7378 // If we have a string, assume it's a code "marker"
7379 // and print some interesting cpu debugging info.
7380 JavaScriptFrameIterator it;
7381 JavaScriptFrame* frame = it.frame();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00007382 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
7383 frame->fp(), frame->sp(), frame->caller_sp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007384 } else {
7385 PrintF("DebugPrint: ");
7386 }
7387 args[0]->Print();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00007388 if (args[0]->IsHeapObject()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007389 PrintF("\n");
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00007390 HeapObject::cast(args[0])->map()->Print();
7391 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007392#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007393 // ShortPrint is available in release mode. Print is not.
7394 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007395#endif
7396 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00007397 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007398
7399 return args[0]; // return TOS
7400}
7401
7402
lrn@chromium.org303ada72010-10-27 09:33:13 +00007403static MaybeObject* Runtime_DebugTrace(Arguments args) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007404 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007405 NoHandleAllocation ha;
7406 Top::PrintStack();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007407 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007408}
7409
7410
lrn@chromium.org303ada72010-10-27 09:33:13 +00007411static MaybeObject* Runtime_DateCurrentTime(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007412 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00007413 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007414
7415 // According to ECMA-262, section 15.9.1, page 117, the precision of
7416 // the number in a Date object representing a particular instant in
7417 // time is milliseconds. Therefore, we floor the result of getting
7418 // the OS time.
7419 double millis = floor(OS::TimeCurrentMillis());
7420 return Heap::NumberFromDouble(millis);
7421}
7422
7423
lrn@chromium.org303ada72010-10-27 09:33:13 +00007424static MaybeObject* Runtime_DateParseString(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007425 HandleScope scope;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007426 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007427
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007428 CONVERT_ARG_CHECKED(String, str, 0);
7429 FlattenString(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007430
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007431 CONVERT_ARG_CHECKED(JSArray, output, 1);
7432 RUNTIME_ASSERT(output->HasFastElements());
7433
7434 AssertNoAllocation no_allocation;
7435
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007436 FixedArray* output_array = FixedArray::cast(output->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007437 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
7438 bool result;
ager@chromium.org5ec48922009-05-05 07:25:34 +00007439 if (str->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007440 result = DateParser::Parse(str->ToAsciiVector(), output_array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007441 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00007442 ASSERT(str->IsTwoByteRepresentation());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007443 result = DateParser::Parse(str->ToUC16Vector(), output_array);
7444 }
7445
7446 if (result) {
7447 return *output;
7448 } else {
7449 return Heap::null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007450 }
7451}
7452
7453
lrn@chromium.org303ada72010-10-27 09:33:13 +00007454static MaybeObject* Runtime_DateLocalTimezone(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007455 NoHandleAllocation ha;
7456 ASSERT(args.length() == 1);
7457
7458 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00007459 const char* zone = OS::LocalTimezone(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007460 return Heap::AllocateStringFromUtf8(CStrVector(zone));
7461}
7462
7463
lrn@chromium.org303ada72010-10-27 09:33:13 +00007464static MaybeObject* Runtime_DateLocalTimeOffset(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007465 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00007466 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007467
7468 return Heap::NumberFromDouble(OS::LocalTimeOffset());
7469}
7470
7471
lrn@chromium.org303ada72010-10-27 09:33:13 +00007472static MaybeObject* Runtime_DateDaylightSavingsOffset(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007473 NoHandleAllocation ha;
7474 ASSERT(args.length() == 1);
7475
7476 CONVERT_DOUBLE_CHECKED(x, args[0]);
7477 return Heap::NumberFromDouble(OS::DaylightSavingsOffset(x));
7478}
7479
7480
lrn@chromium.org303ada72010-10-27 09:33:13 +00007481static MaybeObject* Runtime_GlobalReceiver(Arguments args) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007482 ASSERT(args.length() == 1);
7483 Object* global = args[0];
7484 if (!global->IsJSGlobalObject()) return Heap::null_value();
7485 return JSGlobalObject::cast(global)->global_receiver();
7486}
7487
7488
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00007489static MaybeObject* Runtime_ParseJson(Arguments args) {
7490 HandleScope scope;
7491 ASSERT_EQ(1, args.length());
7492 CONVERT_ARG_CHECKED(String, source, 0);
7493
7494 Handle<Object> result = JsonParser::Parse(source);
7495 if (result.is_null()) {
7496 // Syntax error or stack overflow in scanner.
7497 ASSERT(Top::has_pending_exception());
7498 return Failure::Exception();
7499 }
7500 return *result;
7501}
7502
7503
lrn@chromium.org303ada72010-10-27 09:33:13 +00007504static MaybeObject* Runtime_CompileString(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007505 HandleScope scope;
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00007506 ASSERT_EQ(1, args.length());
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00007507 CONVERT_ARG_CHECKED(String, source, 0);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007508
ager@chromium.org381abbb2009-02-25 13:23:22 +00007509 // Compile source string in the global context.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007510 Handle<Context> context(Top::context()->global_context());
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007511 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(source,
7512 context,
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00007513 true);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007514 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007515 Handle<JSFunction> fun =
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007516 Factory::NewFunctionFromSharedFunctionInfo(shared, context, NOT_TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007517 return *fun;
7518}
7519
7520
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00007521static ObjectPair CompileGlobalEval(Handle<String> source,
7522 Handle<Object> receiver) {
7523 // Deal with a normal eval call with a string argument. Compile it
7524 // and return the compiled function bound in the local context.
7525 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
7526 source,
7527 Handle<Context>(Top::context()),
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00007528 Top::context()->IsGlobalContext());
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00007529 if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
7530 Handle<JSFunction> compiled = Factory::NewFunctionFromSharedFunctionInfo(
7531 shared,
7532 Handle<Context>(Top::context()),
7533 NOT_TENURED);
7534 return MakePair(*compiled, *receiver);
7535}
7536
7537
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007538static ObjectPair Runtime_ResolvePossiblyDirectEval(Arguments args) {
7539 ASSERT(args.length() == 3);
7540 if (!args[0]->IsJSFunction()) {
7541 return MakePair(Top::ThrowIllegalOperation(), NULL);
7542 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007543
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007544 HandleScope scope;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007545 Handle<JSFunction> callee = args.at<JSFunction>(0);
7546 Handle<Object> receiver; // Will be overwritten.
7547
7548 // Compute the calling context.
7549 Handle<Context> context = Handle<Context>(Top::context());
7550#ifdef DEBUG
7551 // Make sure Top::context() agrees with the old code that traversed
7552 // the stack frames to compute the context.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007553 StackFrameLocator locator;
7554 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007555 ASSERT(Context::cast(frame->context()) == *context);
7556#endif
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007557
7558 // Find where the 'eval' symbol is bound. It is unaliased only if
7559 // it is bound in the global context.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007560 int index = -1;
7561 PropertyAttributes attributes = ABSENT;
7562 while (true) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007563 receiver = context->Lookup(Factory::eval_symbol(), FOLLOW_PROTOTYPE_CHAIN,
7564 &index, &attributes);
iposva@chromium.org245aa852009-02-10 00:49:54 +00007565 // Stop search when eval is found or when the global context is
7566 // reached.
7567 if (attributes != ABSENT || context->IsGlobalContext()) break;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007568 if (context->is_function_context()) {
7569 context = Handle<Context>(Context::cast(context->closure()->context()));
7570 } else {
7571 context = Handle<Context>(context->previous());
7572 }
7573 }
7574
iposva@chromium.org245aa852009-02-10 00:49:54 +00007575 // If eval could not be resolved, it has been deleted and we need to
7576 // throw a reference error.
7577 if (attributes == ABSENT) {
7578 Handle<Object> name = Factory::eval_symbol();
7579 Handle<Object> reference_error =
7580 Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007581 return MakePair(Top::Throw(*reference_error), NULL);
iposva@chromium.org245aa852009-02-10 00:49:54 +00007582 }
7583
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007584 if (!context->IsGlobalContext()) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007585 // 'eval' is not bound in the global context. Just call the function
7586 // with the given arguments. This is not necessarily the global eval.
7587 if (receiver->IsContext()) {
7588 context = Handle<Context>::cast(receiver);
7589 receiver = Handle<Object>(context->get(index));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007590 } else if (receiver->IsJSContextExtensionObject()) {
7591 receiver = Handle<JSObject>(Top::context()->global()->global_receiver());
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007592 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007593 return MakePair(*callee, *receiver);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007594 }
7595
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007596 // 'eval' is bound in the global context, but it may have been overwritten.
7597 // Compare it to the builtin 'GlobalEval' function to make sure.
7598 if (*callee != Top::global_context()->global_eval_fun() ||
7599 !args[1]->IsString()) {
7600 return MakePair(*callee, Top::context()->global()->global_receiver());
7601 }
7602
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00007603 return CompileGlobalEval(args.at<String>(1), args.at<Object>(2));
7604}
7605
7606
7607static ObjectPair Runtime_ResolvePossiblyDirectEvalNoLookup(Arguments args) {
7608 ASSERT(args.length() == 3);
7609 if (!args[0]->IsJSFunction()) {
7610 return MakePair(Top::ThrowIllegalOperation(), NULL);
7611 }
7612
7613 HandleScope scope;
7614 Handle<JSFunction> callee = args.at<JSFunction>(0);
7615
7616 // 'eval' is bound in the global context, but it may have been overwritten.
7617 // Compare it to the builtin 'GlobalEval' function to make sure.
7618 if (*callee != Top::global_context()->global_eval_fun() ||
7619 !args[1]->IsString()) {
7620 return MakePair(*callee, Top::context()->global()->global_receiver());
7621 }
7622
7623 return CompileGlobalEval(args.at<String>(1), args.at<Object>(2));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007624}
7625
7626
lrn@chromium.org303ada72010-10-27 09:33:13 +00007627static MaybeObject* Runtime_SetNewFunctionAttributes(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007628 // This utility adjusts the property attributes for newly created Function
7629 // object ("new Function(...)") by changing the map.
7630 // All it does is changing the prototype property to enumerable
7631 // as specified in ECMA262, 15.3.5.2.
7632 HandleScope scope;
7633 ASSERT(args.length() == 1);
7634 CONVERT_ARG_CHECKED(JSFunction, func, 0);
7635 ASSERT(func->map()->instance_type() ==
7636 Top::function_instance_map()->instance_type());
7637 ASSERT(func->map()->instance_size() ==
7638 Top::function_instance_map()->instance_size());
7639 func->set_map(*Top::function_instance_map());
7640 return *func;
7641}
7642
7643
lrn@chromium.org303ada72010-10-27 09:33:13 +00007644static MaybeObject* Runtime_AllocateInNewSpace(Arguments args) {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00007645 // Allocate a block of memory in NewSpace (filled with a filler).
7646 // Use as fallback for allocation in generated code when NewSpace
7647 // is full.
7648 ASSERT(args.length() == 1);
7649 CONVERT_ARG_CHECKED(Smi, size_smi, 0);
7650 int size = size_smi->value();
7651 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
7652 RUNTIME_ASSERT(size > 0);
7653 static const int kMinFreeNewSpaceAfterGC =
7654 Heap::InitialSemiSpaceSize() * 3/4;
7655 RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007656 Object* allocation;
7657 { MaybeObject* maybe_allocation = Heap::new_space()->AllocateRaw(size);
7658 if (maybe_allocation->ToObject(&allocation)) {
7659 Heap::CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
7660 }
7661 return maybe_allocation;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00007662 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00007663}
7664
7665
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007666// Push an object unto an array of objects if it is not already in the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007667// array. Returns true if the element was pushed on the stack and
7668// false otherwise.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007669static MaybeObject* Runtime_PushIfAbsent(Arguments args) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007670 ASSERT(args.length() == 2);
7671 CONVERT_CHECKED(JSArray, array, args[0]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007672 CONVERT_CHECKED(JSObject, element, args[1]);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007673 RUNTIME_ASSERT(array->HasFastElements());
7674 int length = Smi::cast(array->length())->value();
7675 FixedArray* elements = FixedArray::cast(array->elements());
7676 for (int i = 0; i < length; i++) {
7677 if (elements->get(i) == element) return Heap::false_value();
7678 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00007679 Object* obj;
7680 { MaybeObject* maybe_obj = array->SetFastElement(length, element);
7681 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7682 }
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007683 return Heap::true_value();
7684}
7685
7686
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007687/**
7688 * A simple visitor visits every element of Array's.
7689 * The backend storage can be a fixed array for fast elements case,
7690 * or a dictionary for sparse array. Since Dictionary is a subtype
7691 * of FixedArray, the class can be used by both fast and slow cases.
7692 * The second parameter of the constructor, fast_elements, specifies
7693 * whether the storage is a FixedArray or Dictionary.
7694 *
7695 * An index limit is used to deal with the situation that a result array
7696 * length overflows 32-bit non-negative integer.
7697 */
7698class ArrayConcatVisitor {
7699 public:
7700 ArrayConcatVisitor(Handle<FixedArray> storage,
7701 uint32_t index_limit,
7702 bool fast_elements) :
7703 storage_(storage), index_limit_(index_limit),
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007704 index_offset_(0), fast_elements_(fast_elements) { }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007705
7706 void visit(uint32_t i, Handle<Object> elm) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007707 if (i >= index_limit_ - index_offset_) return;
7708 uint32_t index = index_offset_ + i;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007709
7710 if (fast_elements_) {
7711 ASSERT(index < static_cast<uint32_t>(storage_->length()));
7712 storage_->set(index, *elm);
7713
7714 } else {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00007715 Handle<NumberDictionary> dict = Handle<NumberDictionary>::cast(storage_);
7716 Handle<NumberDictionary> result =
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007717 Factory::DictionaryAtNumberPut(dict, index, elm);
7718 if (!result.is_identical_to(dict))
7719 storage_ = result;
7720 }
7721 }
7722
7723 void increase_index_offset(uint32_t delta) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007724 if (index_limit_ - index_offset_ < delta) {
7725 index_offset_ = index_limit_;
7726 } else {
7727 index_offset_ += delta;
7728 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007729 }
7730
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00007731 Handle<FixedArray> storage() { return storage_; }
7732
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007733 private:
7734 Handle<FixedArray> storage_;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007735 // Limit on the accepted indices. Elements with indices larger than the
7736 // limit are ignored by the visitor.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007737 uint32_t index_limit_;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007738 // Index after last seen index. Always less than or equal to index_limit_.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007739 uint32_t index_offset_;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00007740 const bool fast_elements_;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007741};
7742
7743
ager@chromium.org3811b432009-10-28 14:53:37 +00007744template<class ExternalArrayClass, class ElementType>
7745static uint32_t IterateExternalArrayElements(Handle<JSObject> receiver,
7746 bool elements_are_ints,
7747 bool elements_are_guaranteed_smis,
7748 uint32_t range,
7749 ArrayConcatVisitor* visitor) {
7750 Handle<ExternalArrayClass> array(
7751 ExternalArrayClass::cast(receiver->elements()));
7752 uint32_t len = Min(static_cast<uint32_t>(array->length()), range);
7753
7754 if (visitor != NULL) {
7755 if (elements_are_ints) {
7756 if (elements_are_guaranteed_smis) {
7757 for (uint32_t j = 0; j < len; j++) {
7758 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get(j))));
7759 visitor->visit(j, e);
7760 }
7761 } else {
7762 for (uint32_t j = 0; j < len; j++) {
7763 int64_t val = static_cast<int64_t>(array->get(j));
7764 if (Smi::IsValid(static_cast<intptr_t>(val))) {
7765 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
7766 visitor->visit(j, e);
7767 } else {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007768 Handle<Object> e =
7769 Factory::NewNumber(static_cast<ElementType>(val));
ager@chromium.org3811b432009-10-28 14:53:37 +00007770 visitor->visit(j, e);
7771 }
7772 }
7773 }
7774 } else {
7775 for (uint32_t j = 0; j < len; j++) {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007776 Handle<Object> e = Factory::NewNumber(array->get(j));
ager@chromium.org3811b432009-10-28 14:53:37 +00007777 visitor->visit(j, e);
7778 }
7779 }
7780 }
7781
7782 return len;
7783}
7784
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007785/**
7786 * A helper function that visits elements of a JSObject. Only elements
7787 * whose index between 0 and range (exclusive) are visited.
7788 *
7789 * If the third parameter, visitor, is not NULL, the visitor is called
7790 * with parameters, 'visitor_index_offset + element index' and the element.
7791 *
7792 * It returns the number of visisted elements.
7793 */
7794static uint32_t IterateElements(Handle<JSObject> receiver,
7795 uint32_t range,
7796 ArrayConcatVisitor* visitor) {
7797 uint32_t num_of_elements = 0;
7798
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007799 switch (receiver->GetElementsKind()) {
7800 case JSObject::FAST_ELEMENTS: {
7801 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
7802 uint32_t len = elements->length();
7803 if (range < len) {
7804 len = range;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007805 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007806
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007807 for (uint32_t j = 0; j < len; j++) {
7808 Handle<Object> e(elements->get(j));
7809 if (!e->IsTheHole()) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007810 num_of_elements++;
7811 if (visitor) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007812 visitor->visit(j, e);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007813 }
7814 }
7815 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007816 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007817 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007818 case JSObject::PIXEL_ELEMENTS: {
7819 Handle<PixelArray> pixels(PixelArray::cast(receiver->elements()));
7820 uint32_t len = pixels->length();
7821 if (range < len) {
7822 len = range;
7823 }
7824
7825 for (uint32_t j = 0; j < len; j++) {
7826 num_of_elements++;
7827 if (visitor != NULL) {
7828 Handle<Smi> e(Smi::FromInt(pixels->get(j)));
7829 visitor->visit(j, e);
7830 }
7831 }
7832 break;
7833 }
ager@chromium.org3811b432009-10-28 14:53:37 +00007834 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
7835 num_of_elements =
7836 IterateExternalArrayElements<ExternalByteArray, int8_t>(
7837 receiver, true, true, range, visitor);
7838 break;
7839 }
7840 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
7841 num_of_elements =
7842 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
7843 receiver, true, true, range, visitor);
7844 break;
7845 }
7846 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
7847 num_of_elements =
7848 IterateExternalArrayElements<ExternalShortArray, int16_t>(
7849 receiver, true, true, range, visitor);
7850 break;
7851 }
7852 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
7853 num_of_elements =
7854 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
7855 receiver, true, true, range, visitor);
7856 break;
7857 }
7858 case JSObject::EXTERNAL_INT_ELEMENTS: {
7859 num_of_elements =
7860 IterateExternalArrayElements<ExternalIntArray, int32_t>(
7861 receiver, true, false, range, visitor);
7862 break;
7863 }
7864 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
7865 num_of_elements =
7866 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
7867 receiver, true, false, range, visitor);
7868 break;
7869 }
7870 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
7871 num_of_elements =
7872 IterateExternalArrayElements<ExternalFloatArray, float>(
7873 receiver, false, false, range, visitor);
7874 break;
7875 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007876 case JSObject::DICTIONARY_ELEMENTS: {
7877 Handle<NumberDictionary> dict(receiver->element_dictionary());
7878 uint32_t capacity = dict->Capacity();
7879 for (uint32_t j = 0; j < capacity; j++) {
7880 Handle<Object> k(dict->KeyAt(j));
7881 if (dict->IsKey(*k)) {
7882 ASSERT(k->IsNumber());
7883 uint32_t index = static_cast<uint32_t>(k->Number());
7884 if (index < range) {
7885 num_of_elements++;
7886 if (visitor) {
7887 visitor->visit(index, Handle<Object>(dict->ValueAt(j)));
7888 }
7889 }
7890 }
7891 }
7892 break;
7893 }
7894 default:
7895 UNREACHABLE();
7896 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007897 }
7898
7899 return num_of_elements;
7900}
7901
7902
7903/**
7904 * A helper function that visits elements of an Array object, and elements
7905 * on its prototypes.
7906 *
7907 * Elements on prototypes are visited first, and only elements whose indices
7908 * less than Array length are visited.
7909 *
7910 * If a ArrayConcatVisitor object is given, the visitor is called with
7911 * parameters, element's index + visitor_index_offset and the element.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007912 *
7913 * The returned number of elements is an upper bound on the actual number
7914 * of elements added. If the same element occurs in more than one object
7915 * in the array's prototype chain, it will be counted more than once, but
7916 * will only occur once in the result.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007917 */
7918static uint32_t IterateArrayAndPrototypeElements(Handle<JSArray> array,
7919 ArrayConcatVisitor* visitor) {
7920 uint32_t range = static_cast<uint32_t>(array->length()->Number());
7921 Handle<Object> obj = array;
7922
7923 static const int kEstimatedPrototypes = 3;
7924 List< Handle<JSObject> > objects(kEstimatedPrototypes);
7925
7926 // Visit prototype first. If an element on the prototype is shadowed by
7927 // the inheritor using the same index, the ArrayConcatVisitor visits
7928 // the prototype element before the shadowing element.
7929 // The visitor can simply overwrite the old value by new value using
7930 // the same index. This follows Array::concat semantics.
7931 while (!obj->IsNull()) {
7932 objects.Add(Handle<JSObject>::cast(obj));
7933 obj = Handle<Object>(obj->GetPrototype());
7934 }
7935
7936 uint32_t nof_elements = 0;
7937 for (int i = objects.length() - 1; i >= 0; i--) {
7938 Handle<JSObject> obj = objects[i];
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007939 uint32_t encountered_elements =
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007940 IterateElements(Handle<JSObject>::cast(obj), range, visitor);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007941
7942 if (encountered_elements > JSObject::kMaxElementCount - nof_elements) {
7943 nof_elements = JSObject::kMaxElementCount;
7944 } else {
7945 nof_elements += encountered_elements;
7946 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007947 }
7948
7949 return nof_elements;
7950}
7951
7952
7953/**
7954 * A helper function of Runtime_ArrayConcat.
7955 *
7956 * The first argument is an Array of arrays and objects. It is the
7957 * same as the arguments array of Array::concat JS function.
7958 *
7959 * If an argument is an Array object, the function visits array
7960 * elements. If an argument is not an Array object, the function
7961 * visits the object as if it is an one-element array.
7962 *
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007963 * If the result array index overflows 32-bit unsigned integer, the rounded
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007964 * non-negative number is used as new length. For example, if one
7965 * array length is 2^32 - 1, second array length is 1, the
7966 * concatenated array length is 0.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007967 * TODO(lrn) Change length behavior to ECMAScript 5 specification (length
7968 * is one more than the last array index to get a value assigned).
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007969 */
7970static uint32_t IterateArguments(Handle<JSArray> arguments,
7971 ArrayConcatVisitor* visitor) {
7972 uint32_t visited_elements = 0;
7973 uint32_t num_of_args = static_cast<uint32_t>(arguments->length()->Number());
7974
7975 for (uint32_t i = 0; i < num_of_args; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007976 Object *element;
7977 MaybeObject* maybe_element = arguments->GetElement(i);
7978 // This if() is not expected to fail, but we have the check in the
7979 // interest of hardening the runtime calls.
7980 if (maybe_element->ToObject(&element)) {
7981 Handle<Object> obj(element);
7982 if (obj->IsJSArray()) {
7983 Handle<JSArray> array = Handle<JSArray>::cast(obj);
7984 uint32_t len = static_cast<uint32_t>(array->length()->Number());
7985 uint32_t nof_elements =
7986 IterateArrayAndPrototypeElements(array, visitor);
7987 // Total elements of array and its prototype chain can be more than
7988 // the array length, but ArrayConcat can only concatenate at most
7989 // the array length number of elements. We use the length as an estimate
7990 // for the actual number of elements added.
7991 uint32_t added_elements = (nof_elements > len) ? len : nof_elements;
7992 if (JSArray::kMaxElementCount - visited_elements < added_elements) {
7993 visited_elements = JSArray::kMaxElementCount;
7994 } else {
7995 visited_elements += added_elements;
7996 }
7997 if (visitor) visitor->increase_index_offset(len);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007998 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007999 if (visitor) {
8000 visitor->visit(0, obj);
8001 visitor->increase_index_offset(1);
8002 }
8003 if (visited_elements < JSArray::kMaxElementCount) {
8004 visited_elements++;
8005 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008006 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008007 }
8008 }
8009 return visited_elements;
8010}
8011
8012
8013/**
8014 * Array::concat implementation.
8015 * See ECMAScript 262, 15.4.4.4.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008016 * TODO(lrn): Fix non-compliance for very large concatenations and update to
8017 * following the ECMAScript 5 specification.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008018 */
lrn@chromium.org303ada72010-10-27 09:33:13 +00008019static MaybeObject* Runtime_ArrayConcat(Arguments args) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008020 ASSERT(args.length() == 1);
8021 HandleScope handle_scope;
8022
8023 CONVERT_CHECKED(JSArray, arg_arrays, args[0]);
8024 Handle<JSArray> arguments(arg_arrays);
8025
8026 // Pass 1: estimate the number of elements of the result
8027 // (it could be more than real numbers if prototype has elements).
8028 uint32_t result_length = 0;
8029 uint32_t num_of_args = static_cast<uint32_t>(arguments->length()->Number());
8030
8031 { AssertNoAllocation nogc;
8032 for (uint32_t i = 0; i < num_of_args; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008033 Object* obj;
8034 MaybeObject* maybe_object = arguments->GetElement(i);
8035 // This if() is not expected to fail, but we have the check in the
8036 // interest of hardening the runtime calls.
8037 if (maybe_object->ToObject(&obj)) {
8038 uint32_t length_estimate;
8039 if (obj->IsJSArray()) {
8040 length_estimate =
8041 static_cast<uint32_t>(JSArray::cast(obj)->length()->Number());
8042 } else {
8043 length_estimate = 1;
8044 }
8045 if (JSObject::kMaxElementCount - result_length < length_estimate) {
8046 result_length = JSObject::kMaxElementCount;
8047 break;
8048 }
8049 result_length += length_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008050 }
8051 }
8052 }
8053
8054 // Allocate an empty array, will set length and content later.
8055 Handle<JSArray> result = Factory::NewJSArray(0);
8056
8057 uint32_t estimate_nof_elements = IterateArguments(arguments, NULL);
8058 // If estimated number of elements is more than half of length, a
8059 // fixed array (fast case) is more time and space-efficient than a
8060 // dictionary.
8061 bool fast_case = (estimate_nof_elements * 2) >= result_length;
8062
8063 Handle<FixedArray> storage;
8064 if (fast_case) {
8065 // The backing storage array must have non-existing elements to
8066 // preserve holes across concat operations.
8067 storage = Factory::NewFixedArrayWithHoles(result_length);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008068 Handle<Map> fast_map =
8069 Factory::GetFastElementsMap(Handle<Map>(result->map()));
8070 result->set_map(*fast_map);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008071 } else {
8072 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
8073 uint32_t at_least_space_for = estimate_nof_elements +
8074 (estimate_nof_elements >> 2);
8075 storage = Handle<FixedArray>::cast(
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00008076 Factory::NewNumberDictionary(at_least_space_for));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008077 Handle<Map> slow_map =
8078 Factory::GetSlowElementsMap(Handle<Map>(result->map()));
8079 result->set_map(*slow_map);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008080 }
8081
8082 Handle<Object> len = Factory::NewNumber(static_cast<double>(result_length));
8083
8084 ArrayConcatVisitor visitor(storage, result_length, fast_case);
8085
8086 IterateArguments(arguments, &visitor);
8087
8088 result->set_length(*len);
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00008089 // Please note the storage might have changed in the visitor.
8090 result->set_elements(*visitor.storage());
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008091
8092 return *result;
8093}
8094
8095
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008096// This will not allocate (flatten the string), but it may run
8097// very slowly for very deeply nested ConsStrings. For debugging use only.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008098static MaybeObject* Runtime_GlobalPrint(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008099 NoHandleAllocation ha;
8100 ASSERT(args.length() == 1);
8101
8102 CONVERT_CHECKED(String, string, args[0]);
8103 StringInputBuffer buffer(string);
8104 while (buffer.has_more()) {
8105 uint16_t character = buffer.GetNext();
8106 PrintF("%c", character);
8107 }
8108 return string;
8109}
8110
ager@chromium.org5ec48922009-05-05 07:25:34 +00008111// Moves all own elements of an object, that are below a limit, to positions
8112// starting at zero. All undefined values are placed after non-undefined values,
8113// and are followed by non-existing element. Does not change the length
8114// property.
8115// Returns the number of non-undefined elements collected.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008116static MaybeObject* Runtime_RemoveArrayHoles(Arguments args) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00008117 ASSERT(args.length() == 2);
8118 CONVERT_CHECKED(JSObject, object, args[0]);
8119 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
8120 return object->PrepareElementsForSort(limit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008121}
8122
8123
8124// Move contents of argument 0 (an array) to argument 1 (an array)
lrn@chromium.org303ada72010-10-27 09:33:13 +00008125static MaybeObject* Runtime_MoveArrayContents(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008126 ASSERT(args.length() == 2);
8127 CONVERT_CHECKED(JSArray, from, args[0]);
8128 CONVERT_CHECKED(JSArray, to, args[1]);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00008129 HeapObject* new_elements = from->elements();
lrn@chromium.org303ada72010-10-27 09:33:13 +00008130 MaybeObject* maybe_new_map;
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00008131 if (new_elements->map() == Heap::fixed_array_map() ||
8132 new_elements->map() == Heap::fixed_cow_array_map()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008133 maybe_new_map = to->map()->GetFastElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00008134 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008135 maybe_new_map = to->map()->GetSlowElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00008136 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00008137 Object* new_map;
8138 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00008139 to->set_map(Map::cast(new_map));
8140 to->set_elements(new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008141 to->set_length(from->length());
lrn@chromium.org303ada72010-10-27 09:33:13 +00008142 Object* obj;
8143 { MaybeObject* maybe_obj = from->ResetElements();
8144 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8145 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008146 from->set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008147 return to;
8148}
8149
8150
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008151// How many elements does this object/array have?
lrn@chromium.org303ada72010-10-27 09:33:13 +00008152static MaybeObject* Runtime_EstimateNumberOfElements(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008153 ASSERT(args.length() == 1);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008154 CONVERT_CHECKED(JSObject, object, args[0]);
8155 HeapObject* elements = object->elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008156 if (elements->IsDictionary()) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00008157 return Smi::FromInt(NumberDictionary::cast(elements)->NumberOfElements());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008158 } else if (object->IsJSArray()) {
8159 return JSArray::cast(object)->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008160 } else {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008161 return Smi::FromInt(FixedArray::cast(elements)->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008162 }
8163}
8164
8165
lrn@chromium.org303ada72010-10-27 09:33:13 +00008166static MaybeObject* Runtime_SwapElements(Arguments args) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008167 HandleScope handle_scope;
8168
8169 ASSERT_EQ(3, args.length());
8170
ager@chromium.orgac091b72010-05-05 07:34:42 +00008171 CONVERT_ARG_CHECKED(JSObject, object, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008172 Handle<Object> key1 = args.at<Object>(1);
8173 Handle<Object> key2 = args.at<Object>(2);
8174
8175 uint32_t index1, index2;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008176 if (!key1->ToArrayIndex(&index1)
8177 || !key2->ToArrayIndex(&index2)) {
ager@chromium.orgac091b72010-05-05 07:34:42 +00008178 return Top::ThrowIllegalOperation();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008179 }
8180
ager@chromium.orgac091b72010-05-05 07:34:42 +00008181 Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
8182 Handle<Object> tmp1 = GetElement(jsobject, index1);
8183 Handle<Object> tmp2 = GetElement(jsobject, index2);
8184
8185 SetElement(jsobject, index1, tmp2);
8186 SetElement(jsobject, index2, tmp1);
8187
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008188 return Heap::undefined_value();
8189}
8190
8191
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008192// Returns an array that tells you where in the [0, length) interval an array
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008193// might have elements. Can either return keys (positive integers) or
8194// intervals (pair of a negative integer (-start-1) followed by a
8195// positive (length)) or undefined values.
8196// Intervals can span over some keys that are not in the object.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008197static MaybeObject* Runtime_GetArrayKeys(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008198 ASSERT(args.length() == 2);
8199 HandleScope scope;
ager@chromium.org5ec48922009-05-05 07:25:34 +00008200 CONVERT_ARG_CHECKED(JSObject, array, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008201 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008202 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008203 // Create an array and get all the keys into it, then remove all the
8204 // keys that are not integers in the range 0 to length-1.
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008205 Handle<FixedArray> keys = GetKeysInFixedArrayFor(array, INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008206 int keys_length = keys->length();
8207 for (int i = 0; i < keys_length; i++) {
8208 Object* key = keys->get(i);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008209 uint32_t index = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008210 if (!key->ToArrayIndex(&index) || index >= length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008211 // Zap invalid keys.
8212 keys->set_undefined(i);
8213 }
8214 }
8215 return *Factory::NewJSArrayWithElements(keys);
8216 } else {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008217 ASSERT(array->HasFastElements());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008218 Handle<FixedArray> single_interval = Factory::NewFixedArray(2);
8219 // -1 means start of array.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008220 single_interval->set(0, Smi::FromInt(-1));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008221 uint32_t actual_length =
8222 static_cast<uint32_t>(FixedArray::cast(array->elements())->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +00008223 uint32_t min_length = actual_length < length ? actual_length : length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008224 Handle<Object> length_object =
ager@chromium.org5ec48922009-05-05 07:25:34 +00008225 Factory::NewNumber(static_cast<double>(min_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008226 single_interval->set(1, *length_object);
8227 return *Factory::NewJSArrayWithElements(single_interval);
8228 }
8229}
8230
8231
8232// DefineAccessor takes an optional final argument which is the
8233// property attributes (eg, DONT_ENUM, DONT_DELETE). IMPORTANT: due
8234// to the way accessors are implemented, it is set for both the getter
8235// and setter on the first call to DefineAccessor and ignored on
8236// subsequent calls.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008237static MaybeObject* Runtime_DefineAccessor(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008238 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
8239 // Compute attributes.
8240 PropertyAttributes attributes = NONE;
8241 if (args.length() == 5) {
8242 CONVERT_CHECKED(Smi, attrs, args[4]);
8243 int value = attrs->value();
8244 // Only attribute bits should be set.
8245 ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
8246 attributes = static_cast<PropertyAttributes>(value);
8247 }
8248
8249 CONVERT_CHECKED(JSObject, obj, args[0]);
8250 CONVERT_CHECKED(String, name, args[1]);
8251 CONVERT_CHECKED(Smi, flag, args[2]);
8252 CONVERT_CHECKED(JSFunction, fun, args[3]);
8253 return obj->DefineAccessor(name, flag->value() == 0, fun, attributes);
8254}
8255
8256
lrn@chromium.org303ada72010-10-27 09:33:13 +00008257static MaybeObject* Runtime_LookupAccessor(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008258 ASSERT(args.length() == 3);
8259 CONVERT_CHECKED(JSObject, obj, args[0]);
8260 CONVERT_CHECKED(String, name, args[1]);
8261 CONVERT_CHECKED(Smi, flag, args[2]);
8262 return obj->LookupAccessor(name, flag->value() == 0);
8263}
8264
8265
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008266#ifdef ENABLE_DEBUGGER_SUPPORT
lrn@chromium.org303ada72010-10-27 09:33:13 +00008267static MaybeObject* Runtime_DebugBreak(Arguments args) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008268 ASSERT(args.length() == 0);
8269 return Execution::DebugBreakHelper();
8270}
8271
8272
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008273// Helper functions for wrapping and unwrapping stack frame ids.
8274static Smi* WrapFrameId(StackFrame::Id id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +00008275 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008276 return Smi::FromInt(id >> 2);
8277}
8278
8279
8280static StackFrame::Id UnwrapFrameId(Smi* wrapped) {
8281 return static_cast<StackFrame::Id>(wrapped->value() << 2);
8282}
8283
8284
8285// Adds a JavaScript function as a debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +00008286// args[0]: debug event listener function to set or null or undefined for
8287// clearing the event listener function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008288// args[1]: object supplied during callback
lrn@chromium.org303ada72010-10-27 09:33:13 +00008289static MaybeObject* Runtime_SetDebugEventListener(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008290 ASSERT(args.length() == 2);
iposva@chromium.org245aa852009-02-10 00:49:54 +00008291 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
8292 args[0]->IsUndefined() ||
8293 args[0]->IsNull());
8294 Handle<Object> callback = args.at<Object>(0);
8295 Handle<Object> data = args.at<Object>(1);
8296 Debugger::SetEventListener(callback, data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008297
8298 return Heap::undefined_value();
8299}
8300
8301
lrn@chromium.org303ada72010-10-27 09:33:13 +00008302static MaybeObject* Runtime_Break(Arguments args) {
mads.s.ager31e71382008-08-13 09:32:07 +00008303 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008304 StackGuard::DebugBreak();
8305 return Heap::undefined_value();
8306}
8307
8308
lrn@chromium.org303ada72010-10-27 09:33:13 +00008309static MaybeObject* DebugLookupResultValue(Object* receiver, String* name,
8310 LookupResult* result,
8311 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00008312 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008313 switch (result->type()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008314 case NORMAL:
8315 value = result->holder()->GetNormalizedProperty(result);
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00008316 if (value->IsTheHole()) {
8317 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008318 }
8319 return value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00008320 case FIELD:
8321 value =
8322 JSObject::cast(
8323 result->holder())->FastPropertyAt(result->GetFieldIndex());
8324 if (value->IsTheHole()) {
8325 return Heap::undefined_value();
8326 }
8327 return value;
8328 case CONSTANT_FUNCTION:
8329 return result->GetConstantFunction();
8330 case CALLBACKS: {
8331 Object* structure = result->GetCallbackObject();
kasperl@chromium.org71affb52009-05-26 05:44:31 +00008332 if (structure->IsProxy() || structure->IsAccessorInfo()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008333 MaybeObject* maybe_value = receiver->GetPropertyWithCallback(
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00008334 receiver, structure, name, result->holder());
lrn@chromium.org303ada72010-10-27 09:33:13 +00008335 if (!maybe_value->ToObject(&value)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008336 if (maybe_value->IsRetryAfterGC()) return maybe_value;
lrn@chromium.org303ada72010-10-27 09:33:13 +00008337 ASSERT(maybe_value->IsException());
8338 maybe_value = Top::pending_exception();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00008339 Top::clear_pending_exception();
8340 if (caught_exception != NULL) {
8341 *caught_exception = true;
8342 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00008343 return maybe_value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00008344 }
8345 return value;
8346 } else {
8347 return Heap::undefined_value();
8348 }
8349 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008350 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008351 case MAP_TRANSITION:
8352 case CONSTANT_TRANSITION:
8353 case NULL_DESCRIPTOR:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008354 return Heap::undefined_value();
8355 default:
8356 UNREACHABLE();
8357 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008358 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008359 return Heap::undefined_value();
8360}
8361
8362
ager@chromium.org32912102009-01-16 10:38:43 +00008363// Get debugger related details for an object property.
8364// args[0]: object holding property
8365// args[1]: name of the property
8366//
8367// The array returned contains the following information:
8368// 0: Property value
8369// 1: Property details
8370// 2: Property value is exception
8371// 3: Getter function if defined
8372// 4: Setter function if defined
8373// Items 2-4 are only filled if the property has either a getter or a setter
8374// defined through __defineGetter__ and/or __defineSetter__.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008375static MaybeObject* Runtime_DebugGetPropertyDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008376 HandleScope scope;
8377
8378 ASSERT(args.length() == 2);
8379
8380 CONVERT_ARG_CHECKED(JSObject, obj, 0);
8381 CONVERT_ARG_CHECKED(String, name, 1);
8382
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00008383 // Make sure to set the current context to the context before the debugger was
8384 // entered (if the debugger is entered). The reason for switching context here
8385 // is that for some property lookups (accessors and interceptors) callbacks
8386 // into the embedding application can occour, and the embedding application
8387 // could have the assumption that its own global context is the current
8388 // context and not some internal debugger context.
8389 SaveContext save;
8390 if (Debug::InDebugger()) {
8391 Top::set_context(*Debug::debugger_entry()->GetContext());
8392 }
8393
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008394 // Skip the global proxy as it has no properties and always delegates to the
8395 // real global object.
8396 if (obj->IsJSGlobalProxy()) {
8397 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
8398 }
8399
8400
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008401 // Check if the name is trivially convertible to an index and get the element
8402 // if so.
8403 uint32_t index;
8404 if (name->AsArrayIndex(&index)) {
8405 Handle<FixedArray> details = Factory::NewFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008406 Object* element_or_char;
8407 { MaybeObject* maybe_element_or_char =
8408 Runtime::GetElementOrCharAt(obj, index);
8409 if (!maybe_element_or_char->ToObject(&element_or_char)) {
8410 return maybe_element_or_char;
8411 }
8412 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008413 details->set(0, element_or_char);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008414 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
8415 return *Factory::NewJSArrayWithElements(details);
8416 }
8417
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008418 // Find the number of objects making up this.
8419 int length = LocalPrototypeChainLength(*obj);
8420
8421 // Try local lookup on each of the objects.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008422 Handle<JSObject> jsproto = obj;
8423 for (int i = 0; i < length; i++) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008424 LookupResult result;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008425 jsproto->LocalLookup(*name, &result);
8426 if (result.IsProperty()) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008427 // LookupResult is not GC safe as it holds raw object pointers.
8428 // GC can happen later in this code so put the required fields into
8429 // local variables using handles when required for later use.
8430 PropertyType result_type = result.type();
8431 Handle<Object> result_callback_obj;
8432 if (result_type == CALLBACKS) {
8433 result_callback_obj = Handle<Object>(result.GetCallbackObject());
8434 }
8435 Smi* property_details = result.GetPropertyDetails().AsSmi();
8436 // DebugLookupResultValue can cause GC so details from LookupResult needs
8437 // to be copied to handles before this.
8438 bool caught_exception = false;
lrn@chromium.org303ada72010-10-27 09:33:13 +00008439 Object* raw_value;
8440 { MaybeObject* maybe_raw_value =
8441 DebugLookupResultValue(*obj, *name, &result, &caught_exception);
8442 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
8443 }
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008444 Handle<Object> value(raw_value);
8445
8446 // If the callback object is a fixed array then it contains JavaScript
8447 // getter and/or setter.
8448 bool hasJavaScriptAccessors = result_type == CALLBACKS &&
8449 result_callback_obj->IsFixedArray();
8450 Handle<FixedArray> details =
8451 Factory::NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
8452 details->set(0, *value);
8453 details->set(1, property_details);
8454 if (hasJavaScriptAccessors) {
8455 details->set(2,
8456 caught_exception ? Heap::true_value()
8457 : Heap::false_value());
8458 details->set(3, FixedArray::cast(*result_callback_obj)->get(0));
8459 details->set(4, FixedArray::cast(*result_callback_obj)->get(1));
8460 }
8461
8462 return *Factory::NewJSArrayWithElements(details);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008463 }
8464 if (i < length - 1) {
8465 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
8466 }
8467 }
8468
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008469 return Heap::undefined_value();
8470}
8471
8472
lrn@chromium.org303ada72010-10-27 09:33:13 +00008473static MaybeObject* Runtime_DebugGetProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008474 HandleScope scope;
8475
8476 ASSERT(args.length() == 2);
8477
8478 CONVERT_ARG_CHECKED(JSObject, obj, 0);
8479 CONVERT_ARG_CHECKED(String, name, 1);
8480
8481 LookupResult result;
8482 obj->Lookup(*name, &result);
8483 if (result.IsProperty()) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +00008484 return DebugLookupResultValue(*obj, *name, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008485 }
8486 return Heap::undefined_value();
8487}
8488
8489
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008490// Return the property type calculated from the property details.
8491// args[0]: smi with property details.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008492static MaybeObject* Runtime_DebugPropertyTypeFromDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008493 ASSERT(args.length() == 1);
8494 CONVERT_CHECKED(Smi, details, args[0]);
8495 PropertyType type = PropertyDetails(details).type();
8496 return Smi::FromInt(static_cast<int>(type));
8497}
8498
8499
8500// Return the property attribute calculated from the property details.
8501// args[0]: smi with property details.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008502static MaybeObject* Runtime_DebugPropertyAttributesFromDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008503 ASSERT(args.length() == 1);
8504 CONVERT_CHECKED(Smi, details, args[0]);
8505 PropertyAttributes attributes = PropertyDetails(details).attributes();
8506 return Smi::FromInt(static_cast<int>(attributes));
8507}
8508
8509
8510// Return the property insertion index calculated from the property details.
8511// args[0]: smi with property details.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008512static MaybeObject* Runtime_DebugPropertyIndexFromDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008513 ASSERT(args.length() == 1);
8514 CONVERT_CHECKED(Smi, details, args[0]);
8515 int index = PropertyDetails(details).index();
8516 return Smi::FromInt(index);
8517}
8518
8519
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008520// Return property value from named interceptor.
8521// args[0]: object
8522// args[1]: property name
lrn@chromium.org303ada72010-10-27 09:33:13 +00008523static MaybeObject* Runtime_DebugNamedInterceptorPropertyValue(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008524 HandleScope scope;
8525 ASSERT(args.length() == 2);
8526 CONVERT_ARG_CHECKED(JSObject, obj, 0);
8527 RUNTIME_ASSERT(obj->HasNamedInterceptor());
8528 CONVERT_ARG_CHECKED(String, name, 1);
8529
8530 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008531 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008532}
8533
8534
8535// Return element value from indexed interceptor.
8536// args[0]: object
8537// args[1]: index
lrn@chromium.org303ada72010-10-27 09:33:13 +00008538static MaybeObject* Runtime_DebugIndexedInterceptorElementValue(
8539 Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008540 HandleScope scope;
8541 ASSERT(args.length() == 2);
8542 CONVERT_ARG_CHECKED(JSObject, obj, 0);
8543 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
8544 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
8545
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008546 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008547}
8548
8549
lrn@chromium.org303ada72010-10-27 09:33:13 +00008550static MaybeObject* Runtime_CheckExecutionState(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008551 ASSERT(args.length() >= 1);
8552 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +00008553 // Check that the break id is valid.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00008554 if (Debug::break_id() == 0 || break_id != Debug::break_id()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008555 return Top::Throw(Heap::illegal_execution_state_symbol());
8556 }
8557
8558 return Heap::true_value();
8559}
8560
8561
lrn@chromium.org303ada72010-10-27 09:33:13 +00008562static MaybeObject* Runtime_GetFrameCount(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008563 HandleScope scope;
8564 ASSERT(args.length() == 1);
8565
8566 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008567 Object* result;
8568 { MaybeObject* maybe_result = Runtime_CheckExecutionState(args);
8569 if (!maybe_result->ToObject(&result)) return maybe_result;
8570 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008571
8572 // Count all frames which are relevant to debugging stack trace.
8573 int n = 0;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00008574 StackFrame::Id id = Debug::break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00008575 if (id == StackFrame::NO_ID) {
8576 // If there is no JavaScript stack frame count is 0.
8577 return Smi::FromInt(0);
8578 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008579 for (JavaScriptFrameIterator it(id); !it.done(); it.Advance()) n++;
8580 return Smi::FromInt(n);
8581}
8582
8583
8584static const int kFrameDetailsFrameIdIndex = 0;
8585static const int kFrameDetailsReceiverIndex = 1;
8586static const int kFrameDetailsFunctionIndex = 2;
8587static const int kFrameDetailsArgumentCountIndex = 3;
8588static const int kFrameDetailsLocalCountIndex = 4;
8589static const int kFrameDetailsSourcePositionIndex = 5;
8590static const int kFrameDetailsConstructCallIndex = 6;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008591static const int kFrameDetailsAtReturnIndex = 7;
8592static const int kFrameDetailsDebuggerFrameIndex = 8;
8593static const int kFrameDetailsFirstDynamicIndex = 9;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008594
8595// Return an array with frame details
8596// args[0]: number: break id
8597// args[1]: number: frame index
8598//
8599// The array returned contains the following information:
8600// 0: Frame id
8601// 1: Receiver
8602// 2: Function
8603// 3: Argument count
8604// 4: Local count
8605// 5: Source position
8606// 6: Constructor call
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008607// 7: Is at return
8608// 8: Debugger frame
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008609// Arguments name, value
8610// Locals name, value
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008611// Return value if any
lrn@chromium.org303ada72010-10-27 09:33:13 +00008612static MaybeObject* Runtime_GetFrameDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008613 HandleScope scope;
8614 ASSERT(args.length() == 2);
8615
8616 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008617 Object* check;
8618 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
8619 if (!maybe_check->ToObject(&check)) return maybe_check;
8620 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008621 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
8622
8623 // Find the relevant frame with the requested index.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00008624 StackFrame::Id id = Debug::break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00008625 if (id == StackFrame::NO_ID) {
8626 // If there are no JavaScript stack frames return undefined.
8627 return Heap::undefined_value();
8628 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008629 int count = 0;
8630 JavaScriptFrameIterator it(id);
8631 for (; !it.done(); it.Advance()) {
8632 if (count == index) break;
8633 count++;
8634 }
8635 if (it.done()) return Heap::undefined_value();
8636
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008637 bool is_optimized_frame =
8638 it.frame()->code()->kind() == Code::OPTIMIZED_FUNCTION;
8639
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008640 // Traverse the saved contexts chain to find the active context for the
8641 // selected frame.
8642 SaveContext* save = Top::save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008643 while (save != NULL && !save->below(it.frame())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008644 save = save->prev();
8645 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008646 ASSERT(save != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008647
8648 // Get the frame id.
8649 Handle<Object> frame_id(WrapFrameId(it.frame()->id()));
8650
8651 // Find source position.
kasperl@chromium.org061ef742009-02-27 12:16:20 +00008652 int position = it.frame()->code()->SourcePosition(it.frame()->pc());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008653
8654 // Check for constructor frame.
8655 bool constructor = it.frame()->IsConstructor();
8656
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00008657 // Get scope info and read from it for local variable information.
8658 Handle<JSFunction> function(JSFunction::cast(it.frame()->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +00008659 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00008660 ScopeInfo<> info(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008661
8662 // Get the context.
8663 Handle<Context> context(Context::cast(it.frame()->context()));
8664
8665 // Get the locals names and values into a temporary array.
8666 //
8667 // TODO(1240907): Hide compiler-introduced stack variables
8668 // (e.g. .result)? For users of the debugger, they will probably be
8669 // confusing.
8670 Handle<FixedArray> locals = Factory::NewFixedArray(info.NumberOfLocals() * 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008671
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008672 // Fill in the names of the locals.
8673 for (int i = 0; i < info.NumberOfLocals(); i++) {
8674 locals->set(i * 2, *info.LocalName(i));
8675 }
8676
8677 // Fill in the values of the locals.
8678 for (int i = 0; i < info.NumberOfLocals(); i++) {
8679 if (is_optimized_frame) {
8680 // If we are inspecting an optimized frame use undefined as the
8681 // value for all locals.
8682 //
8683 // TODO(3141533): We should be able to get the correct values
8684 // for locals in optimized frames.
8685 locals->set(i * 2 + 1, Heap::undefined_value());
8686 } else if (i < info.number_of_stack_slots()) {
8687 // Get the value from the stack.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008688 locals->set(i * 2 + 1, it.frame()->GetExpression(i));
8689 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008690 // Traverse the context chain to the function context as all local
8691 // variables stored in the context will be on the function context.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008692 Handle<String> name = info.LocalName(i);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008693 while (!context->is_function_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008694 context = Handle<Context>(context->previous());
8695 }
8696 ASSERT(context->is_function_context());
8697 locals->set(i * 2 + 1,
ager@chromium.orgb5737492010-07-15 09:29:43 +00008698 context->get(scope_info->ContextSlotIndex(*name, NULL)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008699 }
8700 }
8701
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008702 // Check whether this frame is positioned at return. If not top
8703 // frame or if the frame is optimized it cannot be at a return.
8704 bool at_return = false;
8705 if (!is_optimized_frame && index == 0) {
8706 at_return = Debug::IsBreakAtReturn(it.frame());
8707 }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008708
8709 // If positioned just before return find the value to be returned and add it
8710 // to the frame information.
8711 Handle<Object> return_value = Factory::undefined_value();
8712 if (at_return) {
8713 StackFrameIterator it2;
8714 Address internal_frame_sp = NULL;
8715 while (!it2.done()) {
8716 if (it2.frame()->is_internal()) {
8717 internal_frame_sp = it2.frame()->sp();
8718 } else {
8719 if (it2.frame()->is_java_script()) {
8720 if (it2.frame()->id() == it.frame()->id()) {
8721 // The internal frame just before the JavaScript frame contains the
8722 // value to return on top. A debug break at return will create an
8723 // internal frame to store the return value (eax/rax/r0) before
8724 // entering the debug break exit frame.
8725 if (internal_frame_sp != NULL) {
8726 return_value =
8727 Handle<Object>(Memory::Object_at(internal_frame_sp));
8728 break;
8729 }
8730 }
8731 }
8732
8733 // Indicate that the previous frame was not an internal frame.
8734 internal_frame_sp = NULL;
8735 }
8736 it2.Advance();
8737 }
8738 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008739
8740 // Now advance to the arguments adapter frame (if any). It contains all
8741 // the provided parameters whereas the function frame always have the number
8742 // of arguments matching the functions parameters. The rest of the
8743 // information (except for what is collected above) is the same.
8744 it.AdvanceToArgumentsFrame();
8745
8746 // Find the number of arguments to fill. At least fill the number of
8747 // parameters for the function and fill more if more parameters are provided.
8748 int argument_count = info.number_of_parameters();
8749 if (argument_count < it.frame()->GetProvidedParametersCount()) {
8750 argument_count = it.frame()->GetProvidedParametersCount();
8751 }
8752
8753 // Calculate the size of the result.
8754 int details_size = kFrameDetailsFirstDynamicIndex +
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008755 2 * (argument_count + info.NumberOfLocals()) +
8756 (at_return ? 1 : 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008757 Handle<FixedArray> details = Factory::NewFixedArray(details_size);
8758
8759 // Add the frame id.
8760 details->set(kFrameDetailsFrameIdIndex, *frame_id);
8761
8762 // Add the function (same as in function frame).
8763 details->set(kFrameDetailsFunctionIndex, it.frame()->function());
8764
8765 // Add the arguments count.
8766 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
8767
8768 // Add the locals count
8769 details->set(kFrameDetailsLocalCountIndex,
8770 Smi::FromInt(info.NumberOfLocals()));
8771
8772 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +00008773 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008774 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
8775 } else {
8776 details->set(kFrameDetailsSourcePositionIndex, Heap::undefined_value());
8777 }
8778
8779 // Add the constructor information.
8780 details->set(kFrameDetailsConstructCallIndex, Heap::ToBoolean(constructor));
8781
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008782 // Add the at return information.
8783 details->set(kFrameDetailsAtReturnIndex, Heap::ToBoolean(at_return));
8784
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008785 // Add information on whether this frame is invoked in the debugger context.
8786 details->set(kFrameDetailsDebuggerFrameIndex,
8787 Heap::ToBoolean(*save->context() == *Debug::debug_context()));
8788
8789 // Fill the dynamic part.
8790 int details_index = kFrameDetailsFirstDynamicIndex;
8791
8792 // Add arguments name and value.
8793 for (int i = 0; i < argument_count; i++) {
8794 // Name of the argument.
8795 if (i < info.number_of_parameters()) {
8796 details->set(details_index++, *info.parameter_name(i));
8797 } else {
8798 details->set(details_index++, Heap::undefined_value());
8799 }
8800
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008801 // Parameter value. If we are inspecting an optimized frame, use
8802 // undefined as the value.
8803 //
8804 // TODO(3141533): We should be able to get the actual parameter
8805 // value for optimized frames.
8806 if (!is_optimized_frame &&
8807 (i < it.frame()->GetProvidedParametersCount())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008808 details->set(details_index++, it.frame()->GetParameter(i));
8809 } else {
8810 details->set(details_index++, Heap::undefined_value());
8811 }
8812 }
8813
8814 // Add locals name and value from the temporary copy from the function frame.
8815 for (int i = 0; i < info.NumberOfLocals() * 2; i++) {
8816 details->set(details_index++, locals->get(i));
8817 }
8818
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008819 // Add the value being returned.
8820 if (at_return) {
8821 details->set(details_index++, *return_value);
8822 }
8823
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008824 // Add the receiver (same as in function frame).
8825 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
8826 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
8827 Handle<Object> receiver(it.frame()->receiver());
8828 if (!receiver->IsJSObject()) {
8829 // If the receiver is NOT a JSObject we have hit an optimization
8830 // where a value object is not converted into a wrapped JS objects.
8831 // To hide this optimization from the debugger, we wrap the receiver
8832 // by creating correct wrapper object based on the calling frame's
8833 // global context.
8834 it.Advance();
8835 Handle<Context> calling_frames_global_context(
8836 Context::cast(Context::cast(it.frame()->context())->global_context()));
8837 receiver = Factory::ToObject(receiver, calling_frames_global_context);
8838 }
8839 details->set(kFrameDetailsReceiverIndex, *receiver);
8840
8841 ASSERT_EQ(details_size, details_index);
8842 return *Factory::NewJSArrayWithElements(details);
8843}
8844
8845
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008846// Copy all the context locals into an object used to materialize a scope.
ager@chromium.orgb5737492010-07-15 09:29:43 +00008847static void CopyContextLocalsToScopeObject(
8848 Handle<SerializedScopeInfo> serialized_scope_info,
8849 ScopeInfo<>& scope_info,
8850 Handle<Context> context,
8851 Handle<JSObject> scope_object) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008852 // Fill all context locals to the context extension.
8853 for (int i = Context::MIN_CONTEXT_SLOTS;
8854 i < scope_info.number_of_context_slots();
8855 i++) {
ager@chromium.orgb5737492010-07-15 09:29:43 +00008856 int context_index = serialized_scope_info->ContextSlotIndex(
8857 *scope_info.context_slot_name(i), NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008858
8859 // Don't include the arguments shadow (.arguments) context variable.
8860 if (*scope_info.context_slot_name(i) != Heap::arguments_shadow_symbol()) {
8861 SetProperty(scope_object,
8862 scope_info.context_slot_name(i),
8863 Handle<Object>(context->get(context_index)), NONE);
8864 }
8865 }
8866}
8867
8868
8869// Create a plain JSObject which materializes the local scope for the specified
8870// frame.
8871static Handle<JSObject> MaterializeLocalScope(JavaScriptFrame* frame) {
8872 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00008873 Handle<SharedFunctionInfo> shared(function->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +00008874 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
8875 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008876
8877 // Allocate and initialize a JSObject with all the arguments, stack locals
8878 // heap locals and extension properties of the debugged function.
8879 Handle<JSObject> local_scope = Factory::NewJSObject(Top::object_function());
8880
8881 // First fill all parameters.
8882 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
8883 SetProperty(local_scope,
8884 scope_info.parameter_name(i),
8885 Handle<Object>(frame->GetParameter(i)), NONE);
8886 }
8887
8888 // Second fill all stack locals.
8889 for (int i = 0; i < scope_info.number_of_stack_slots(); i++) {
8890 SetProperty(local_scope,
8891 scope_info.stack_slot_name(i),
8892 Handle<Object>(frame->GetExpression(i)), NONE);
8893 }
8894
8895 // Third fill all context locals.
8896 Handle<Context> frame_context(Context::cast(frame->context()));
8897 Handle<Context> function_context(frame_context->fcontext());
ager@chromium.orgb5737492010-07-15 09:29:43 +00008898 CopyContextLocalsToScopeObject(serialized_scope_info, scope_info,
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008899 function_context, local_scope);
8900
8901 // Finally copy any properties from the function context extension. This will
8902 // be variables introduced by eval.
8903 if (function_context->closure() == *function) {
8904 if (function_context->has_extension() &&
8905 !function_context->IsGlobalContext()) {
8906 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008907 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008908 for (int i = 0; i < keys->length(); i++) {
8909 // Names of variables introduced by eval are strings.
8910 ASSERT(keys->get(i)->IsString());
8911 Handle<String> key(String::cast(keys->get(i)));
8912 SetProperty(local_scope, key, GetProperty(ext, key), NONE);
8913 }
8914 }
8915 }
8916 return local_scope;
8917}
8918
8919
8920// Create a plain JSObject which materializes the closure content for the
8921// context.
8922static Handle<JSObject> MaterializeClosure(Handle<Context> context) {
8923 ASSERT(context->is_function_context());
8924
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00008925 Handle<SharedFunctionInfo> shared(context->closure()->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +00008926 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
8927 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008928
8929 // Allocate and initialize a JSObject with all the content of theis function
8930 // closure.
8931 Handle<JSObject> closure_scope = Factory::NewJSObject(Top::object_function());
8932
8933 // Check whether the arguments shadow object exists.
8934 int arguments_shadow_index =
ager@chromium.orgb5737492010-07-15 09:29:43 +00008935 shared->scope_info()->ContextSlotIndex(Heap::arguments_shadow_symbol(),
8936 NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008937 if (arguments_shadow_index >= 0) {
8938 // In this case all the arguments are available in the arguments shadow
8939 // object.
8940 Handle<JSObject> arguments_shadow(
8941 JSObject::cast(context->get(arguments_shadow_index)));
8942 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008943 // We don't expect exception-throwing getters on the arguments shadow.
8944 Object* element = arguments_shadow->GetElement(i)->ToObjectUnchecked();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008945 SetProperty(closure_scope,
8946 scope_info.parameter_name(i),
lrn@chromium.org303ada72010-10-27 09:33:13 +00008947 Handle<Object>(element),
8948 NONE);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008949 }
8950 }
8951
8952 // Fill all context locals to the context extension.
ager@chromium.orgb5737492010-07-15 09:29:43 +00008953 CopyContextLocalsToScopeObject(serialized_scope_info, scope_info,
8954 context, closure_scope);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008955
8956 // Finally copy any properties from the function context extension. This will
8957 // be variables introduced by eval.
8958 if (context->has_extension()) {
8959 Handle<JSObject> ext(JSObject::cast(context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008960 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008961 for (int i = 0; i < keys->length(); i++) {
8962 // Names of variables introduced by eval are strings.
8963 ASSERT(keys->get(i)->IsString());
8964 Handle<String> key(String::cast(keys->get(i)));
8965 SetProperty(closure_scope, key, GetProperty(ext, key), NONE);
8966 }
8967 }
8968
8969 return closure_scope;
8970}
8971
8972
8973// Iterate over the actual scopes visible from a stack frame. All scopes are
8974// backed by an actual context except the local scope, which is inserted
8975// "artifically" in the context chain.
8976class ScopeIterator {
8977 public:
8978 enum ScopeType {
8979 ScopeTypeGlobal = 0,
8980 ScopeTypeLocal,
8981 ScopeTypeWith,
ager@chromium.orga1645e22009-09-09 19:27:10 +00008982 ScopeTypeClosure,
8983 // Every catch block contains an implicit with block (its parameter is
8984 // a JSContextExtensionObject) that extends current scope with a variable
8985 // holding exception object. Such with blocks are treated as scopes of their
8986 // own type.
8987 ScopeTypeCatch
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008988 };
8989
8990 explicit ScopeIterator(JavaScriptFrame* frame)
8991 : frame_(frame),
8992 function_(JSFunction::cast(frame->function())),
8993 context_(Context::cast(frame->context())),
8994 local_done_(false),
8995 at_local_(false) {
8996
8997 // Check whether the first scope is actually a local scope.
8998 if (context_->IsGlobalContext()) {
8999 // If there is a stack slot for .result then this local scope has been
9000 // created for evaluating top level code and it is not a real local scope.
9001 // Checking for the existence of .result seems fragile, but the scope info
9002 // saved with the code object does not otherwise have that information.
ager@chromium.orgb5737492010-07-15 09:29:43 +00009003 int index = function_->shared()->scope_info()->
9004 StackSlotIndex(Heap::result_symbol());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009005 at_local_ = index < 0;
9006 } else if (context_->is_function_context()) {
9007 at_local_ = true;
9008 }
9009 }
9010
9011 // More scopes?
9012 bool Done() { return context_.is_null(); }
9013
9014 // Move to the next scope.
9015 void Next() {
9016 // If at a local scope mark the local scope as passed.
9017 if (at_local_) {
9018 at_local_ = false;
9019 local_done_ = true;
9020
9021 // If the current context is not associated with the local scope the
9022 // current context is the next real scope, so don't move to the next
9023 // context in this case.
9024 if (context_->closure() != *function_) {
9025 return;
9026 }
9027 }
9028
9029 // The global scope is always the last in the chain.
9030 if (context_->IsGlobalContext()) {
9031 context_ = Handle<Context>();
9032 return;
9033 }
9034
9035 // Move to the next context.
9036 if (context_->is_function_context()) {
9037 context_ = Handle<Context>(Context::cast(context_->closure()->context()));
9038 } else {
9039 context_ = Handle<Context>(context_->previous());
9040 }
9041
9042 // If passing the local scope indicate that the current scope is now the
9043 // local scope.
9044 if (!local_done_ &&
9045 (context_->IsGlobalContext() || (context_->is_function_context()))) {
9046 at_local_ = true;
9047 }
9048 }
9049
9050 // Return the type of the current scope.
9051 int Type() {
9052 if (at_local_) {
9053 return ScopeTypeLocal;
9054 }
9055 if (context_->IsGlobalContext()) {
9056 ASSERT(context_->global()->IsGlobalObject());
9057 return ScopeTypeGlobal;
9058 }
9059 if (context_->is_function_context()) {
9060 return ScopeTypeClosure;
9061 }
9062 ASSERT(context_->has_extension());
ager@chromium.orga1645e22009-09-09 19:27:10 +00009063 // Current scope is either an explicit with statement or a with statement
9064 // implicitely generated for a catch block.
9065 // If the extension object here is a JSContextExtensionObject then
9066 // current with statement is one frome a catch block otherwise it's a
9067 // regular with statement.
9068 if (context_->extension()->IsJSContextExtensionObject()) {
9069 return ScopeTypeCatch;
9070 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009071 return ScopeTypeWith;
9072 }
9073
9074 // Return the JavaScript object with the content of the current scope.
9075 Handle<JSObject> ScopeObject() {
9076 switch (Type()) {
9077 case ScopeIterator::ScopeTypeGlobal:
9078 return Handle<JSObject>(CurrentContext()->global());
9079 break;
9080 case ScopeIterator::ScopeTypeLocal:
9081 // Materialize the content of the local scope into a JSObject.
9082 return MaterializeLocalScope(frame_);
9083 break;
9084 case ScopeIterator::ScopeTypeWith:
ager@chromium.orga1645e22009-09-09 19:27:10 +00009085 case ScopeIterator::ScopeTypeCatch:
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009086 // Return the with object.
9087 return Handle<JSObject>(CurrentContext()->extension());
9088 break;
9089 case ScopeIterator::ScopeTypeClosure:
9090 // Materialize the content of the closure scope into a JSObject.
9091 return MaterializeClosure(CurrentContext());
9092 break;
9093 }
9094 UNREACHABLE();
9095 return Handle<JSObject>();
9096 }
9097
9098 // Return the context for this scope. For the local context there might not
9099 // be an actual context.
9100 Handle<Context> CurrentContext() {
9101 if (at_local_ && context_->closure() != *function_) {
9102 return Handle<Context>();
9103 }
9104 return context_;
9105 }
9106
9107#ifdef DEBUG
9108 // Debug print of the content of the current scope.
9109 void DebugPrint() {
9110 switch (Type()) {
9111 case ScopeIterator::ScopeTypeGlobal:
9112 PrintF("Global:\n");
9113 CurrentContext()->Print();
9114 break;
9115
9116 case ScopeIterator::ScopeTypeLocal: {
9117 PrintF("Local:\n");
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009118 ScopeInfo<> scope_info(function_->shared()->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009119 scope_info.Print();
9120 if (!CurrentContext().is_null()) {
9121 CurrentContext()->Print();
9122 if (CurrentContext()->has_extension()) {
9123 Handle<JSObject> extension =
9124 Handle<JSObject>(CurrentContext()->extension());
9125 if (extension->IsJSContextExtensionObject()) {
9126 extension->Print();
9127 }
9128 }
9129 }
9130 break;
9131 }
9132
9133 case ScopeIterator::ScopeTypeWith: {
9134 PrintF("With:\n");
9135 Handle<JSObject> extension =
9136 Handle<JSObject>(CurrentContext()->extension());
9137 extension->Print();
9138 break;
9139 }
9140
ager@chromium.orga1645e22009-09-09 19:27:10 +00009141 case ScopeIterator::ScopeTypeCatch: {
9142 PrintF("Catch:\n");
9143 Handle<JSObject> extension =
9144 Handle<JSObject>(CurrentContext()->extension());
9145 extension->Print();
9146 break;
9147 }
9148
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009149 case ScopeIterator::ScopeTypeClosure: {
9150 PrintF("Closure:\n");
9151 CurrentContext()->Print();
9152 if (CurrentContext()->has_extension()) {
9153 Handle<JSObject> extension =
9154 Handle<JSObject>(CurrentContext()->extension());
9155 if (extension->IsJSContextExtensionObject()) {
9156 extension->Print();
9157 }
9158 }
9159 break;
9160 }
9161
9162 default:
9163 UNREACHABLE();
9164 }
9165 PrintF("\n");
9166 }
9167#endif
9168
9169 private:
9170 JavaScriptFrame* frame_;
9171 Handle<JSFunction> function_;
9172 Handle<Context> context_;
9173 bool local_done_;
9174 bool at_local_;
9175
9176 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
9177};
9178
9179
lrn@chromium.org303ada72010-10-27 09:33:13 +00009180static MaybeObject* Runtime_GetScopeCount(Arguments args) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009181 HandleScope scope;
9182 ASSERT(args.length() == 2);
9183
9184 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009185 Object* check;
9186 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
9187 if (!maybe_check->ToObject(&check)) return maybe_check;
9188 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009189 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
9190
9191 // Get the frame where the debugging is performed.
9192 StackFrame::Id id = UnwrapFrameId(wrapped_id);
9193 JavaScriptFrameIterator it(id);
9194 JavaScriptFrame* frame = it.frame();
9195
9196 // Count the visible scopes.
9197 int n = 0;
9198 for (ScopeIterator it(frame); !it.Done(); it.Next()) {
9199 n++;
9200 }
9201
9202 return Smi::FromInt(n);
9203}
9204
9205
9206static const int kScopeDetailsTypeIndex = 0;
9207static const int kScopeDetailsObjectIndex = 1;
9208static const int kScopeDetailsSize = 2;
9209
9210// Return an array with scope details
9211// args[0]: number: break id
9212// args[1]: number: frame index
9213// args[2]: number: scope index
9214//
9215// The array returned contains the following information:
9216// 0: Scope type
9217// 1: Scope object
lrn@chromium.org303ada72010-10-27 09:33:13 +00009218static MaybeObject* Runtime_GetScopeDetails(Arguments args) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009219 HandleScope scope;
9220 ASSERT(args.length() == 3);
9221
9222 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009223 Object* check;
9224 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
9225 if (!maybe_check->ToObject(&check)) return maybe_check;
9226 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009227 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
9228 CONVERT_NUMBER_CHECKED(int, index, Int32, args[2]);
9229
9230 // Get the frame where the debugging is performed.
9231 StackFrame::Id id = UnwrapFrameId(wrapped_id);
9232 JavaScriptFrameIterator frame_it(id);
9233 JavaScriptFrame* frame = frame_it.frame();
9234
9235 // Find the requested scope.
9236 int n = 0;
9237 ScopeIterator it(frame);
9238 for (; !it.Done() && n < index; it.Next()) {
9239 n++;
9240 }
9241 if (it.Done()) {
9242 return Heap::undefined_value();
9243 }
9244
9245 // Calculate the size of the result.
9246 int details_size = kScopeDetailsSize;
9247 Handle<FixedArray> details = Factory::NewFixedArray(details_size);
9248
9249 // Fill in scope details.
9250 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00009251 Handle<JSObject> scope_object = it.ScopeObject();
9252 details->set(kScopeDetailsObjectIndex, *scope_object);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009253
9254 return *Factory::NewJSArrayWithElements(details);
9255}
9256
9257
lrn@chromium.org303ada72010-10-27 09:33:13 +00009258static MaybeObject* Runtime_DebugPrintScopes(Arguments args) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009259 HandleScope scope;
9260 ASSERT(args.length() == 0);
9261
9262#ifdef DEBUG
9263 // Print the scopes for the top frame.
9264 StackFrameLocator locator;
9265 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
9266 for (ScopeIterator it(frame); !it.Done(); it.Next()) {
9267 it.DebugPrint();
9268 }
9269#endif
9270 return Heap::undefined_value();
9271}
9272
9273
lrn@chromium.org303ada72010-10-27 09:33:13 +00009274static MaybeObject* Runtime_GetThreadCount(Arguments args) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009275 HandleScope scope;
9276 ASSERT(args.length() == 1);
9277
9278 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009279 Object* result;
9280 { MaybeObject* maybe_result = Runtime_CheckExecutionState(args);
9281 if (!maybe_result->ToObject(&result)) return maybe_result;
9282 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009283
9284 // Count all archived V8 threads.
9285 int n = 0;
9286 for (ThreadState* thread = ThreadState::FirstInUse();
9287 thread != NULL;
9288 thread = thread->Next()) {
9289 n++;
9290 }
9291
9292 // Total number of threads is current thread and archived threads.
9293 return Smi::FromInt(n + 1);
9294}
9295
9296
9297static const int kThreadDetailsCurrentThreadIndex = 0;
9298static const int kThreadDetailsThreadIdIndex = 1;
9299static const int kThreadDetailsSize = 2;
9300
9301// Return an array with thread details
9302// args[0]: number: break id
9303// args[1]: number: thread index
9304//
9305// The array returned contains the following information:
9306// 0: Is current thread?
9307// 1: Thread id
lrn@chromium.org303ada72010-10-27 09:33:13 +00009308static MaybeObject* Runtime_GetThreadDetails(Arguments args) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009309 HandleScope scope;
9310 ASSERT(args.length() == 2);
9311
9312 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009313 Object* check;
9314 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
9315 if (!maybe_check->ToObject(&check)) return maybe_check;
9316 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009317 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
9318
9319 // Allocate array for result.
9320 Handle<FixedArray> details = Factory::NewFixedArray(kThreadDetailsSize);
9321
9322 // Thread index 0 is current thread.
9323 if (index == 0) {
9324 // Fill the details.
9325 details->set(kThreadDetailsCurrentThreadIndex, Heap::true_value());
9326 details->set(kThreadDetailsThreadIdIndex,
9327 Smi::FromInt(ThreadManager::CurrentId()));
9328 } else {
9329 // Find the thread with the requested index.
9330 int n = 1;
9331 ThreadState* thread = ThreadState::FirstInUse();
9332 while (index != n && thread != NULL) {
9333 thread = thread->Next();
9334 n++;
9335 }
9336 if (thread == NULL) {
9337 return Heap::undefined_value();
9338 }
9339
9340 // Fill the details.
9341 details->set(kThreadDetailsCurrentThreadIndex, Heap::false_value());
9342 details->set(kThreadDetailsThreadIdIndex, Smi::FromInt(thread->id()));
9343 }
9344
9345 // Convert to JS array and return.
9346 return *Factory::NewJSArrayWithElements(details);
9347}
9348
9349
whesse@chromium.orge90029b2010-08-02 11:52:17 +00009350// Sets the disable break state
9351// args[0]: disable break state
lrn@chromium.org303ada72010-10-27 09:33:13 +00009352static MaybeObject* Runtime_SetDisableBreak(Arguments args) {
whesse@chromium.orge90029b2010-08-02 11:52:17 +00009353 HandleScope scope;
9354 ASSERT(args.length() == 1);
9355 CONVERT_BOOLEAN_CHECKED(disable_break, args[0]);
9356 Debug::set_disable_break(disable_break);
9357 return Heap::undefined_value();
9358}
9359
9360
lrn@chromium.org303ada72010-10-27 09:33:13 +00009361static MaybeObject* Runtime_GetBreakLocations(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009362 HandleScope scope;
9363 ASSERT(args.length() == 1);
9364
ager@chromium.org5aa501c2009-06-23 07:57:28 +00009365 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
9366 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009367 // Find the number of break points
9368 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
9369 if (break_locations->IsUndefined()) return Heap::undefined_value();
9370 // Return array as JS array
9371 return *Factory::NewJSArrayWithElements(
9372 Handle<FixedArray>::cast(break_locations));
9373}
9374
9375
9376// Set a break point in a function
9377// args[0]: function
9378// args[1]: number: break source position (within the function source)
9379// args[2]: number: break point object
lrn@chromium.org303ada72010-10-27 09:33:13 +00009380static MaybeObject* Runtime_SetFunctionBreakPoint(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009381 HandleScope scope;
9382 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00009383 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
9384 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009385 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
9386 RUNTIME_ASSERT(source_position >= 0);
9387 Handle<Object> break_point_object_arg = args.at<Object>(2);
9388
9389 // Set break point.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00009390 Debug::SetBreakPoint(shared, break_point_object_arg, &source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009391
lrn@chromium.org32d961d2010-06-30 09:09:34 +00009392 return Smi::FromInt(source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009393}
9394
9395
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00009396Object* Runtime::FindSharedFunctionInfoInScript(Handle<Script> script,
9397 int position) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009398 // Iterate the heap looking for SharedFunctionInfo generated from the
9399 // script. The inner most SharedFunctionInfo containing the source position
9400 // for the requested break point is found.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009401 // NOTE: This might require several heap iterations. If the SharedFunctionInfo
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009402 // which is found is not compiled it is compiled and the heap is iterated
9403 // again as the compilation might create inner functions from the newly
9404 // compiled function and the actual requested break point might be in one of
9405 // these functions.
9406 bool done = false;
9407 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +00009408 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009409 Handle<SharedFunctionInfo> target;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009410 while (!done) {
9411 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009412 for (HeapObject* obj = iterator.next();
9413 obj != NULL; obj = iterator.next()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009414 if (obj->IsSharedFunctionInfo()) {
9415 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
9416 if (shared->script() == *script) {
9417 // If the SharedFunctionInfo found has the requested script data and
9418 // contains the source position it is a candidate.
9419 int start_position = shared->function_token_position();
ager@chromium.org236ad962008-09-25 09:45:57 +00009420 if (start_position == RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009421 start_position = shared->start_position();
9422 }
9423 if (start_position <= position &&
9424 position <= shared->end_position()) {
ager@chromium.org32912102009-01-16 10:38:43 +00009425 // If there is no candidate or this function is within the current
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009426 // candidate this is the new candidate.
9427 if (target.is_null()) {
9428 target_start_position = start_position;
9429 target = shared;
9430 } else {
ager@chromium.orga1645e22009-09-09 19:27:10 +00009431 if (target_start_position == start_position &&
9432 shared->end_position() == target->end_position()) {
9433 // If a top-level function contain only one function
9434 // declartion the source for the top-level and the function is
9435 // the same. In that case prefer the non top-level function.
9436 if (!shared->is_toplevel()) {
9437 target_start_position = start_position;
9438 target = shared;
9439 }
9440 } else if (target_start_position <= start_position &&
9441 shared->end_position() <= target->end_position()) {
9442 // This containment check includes equality as a function inside
9443 // a top-level function can share either start or end position
9444 // with the top-level function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009445 target_start_position = start_position;
9446 target = shared;
9447 }
9448 }
9449 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009450 }
9451 }
9452 }
9453
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009454 if (target.is_null()) {
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00009455 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009456 }
9457
9458 // If the candidate found is compiled we are done. NOTE: when lazy
9459 // compilation of inner functions is introduced some additional checking
9460 // needs to be done here to compile inner functions.
9461 done = target->is_compiled();
9462 if (!done) {
9463 // If the candidate is not compiled compile it to reveal any inner
9464 // functions which might contain the requested source position.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009465 CompileLazyShared(target, KEEP_EXCEPTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009466 }
9467 }
9468
9469 return *target;
9470}
9471
9472
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00009473// Changes the state of a break point in a script and returns source position
9474// where break point was set. NOTE: Regarding performance see the NOTE for
9475// GetScriptFromScriptData.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009476// args[0]: script to set break point in
9477// args[1]: number: break source position (within the script source)
9478// args[2]: number: break point object
lrn@chromium.org303ada72010-10-27 09:33:13 +00009479static MaybeObject* Runtime_SetScriptBreakPoint(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009480 HandleScope scope;
9481 ASSERT(args.length() == 3);
9482 CONVERT_ARG_CHECKED(JSValue, wrapper, 0);
9483 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
9484 RUNTIME_ASSERT(source_position >= 0);
9485 Handle<Object> break_point_object_arg = args.at<Object>(2);
9486
9487 // Get the script from the script wrapper.
9488 RUNTIME_ASSERT(wrapper->value()->IsScript());
9489 Handle<Script> script(Script::cast(wrapper->value()));
9490
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00009491 Object* result = Runtime::FindSharedFunctionInfoInScript(
9492 script, source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009493 if (!result->IsUndefined()) {
9494 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
9495 // Find position within function. The script position might be before the
9496 // source position of the first function.
9497 int position;
9498 if (shared->start_position() > source_position) {
9499 position = 0;
9500 } else {
9501 position = source_position - shared->start_position();
9502 }
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00009503 Debug::SetBreakPoint(shared, break_point_object_arg, &position);
9504 position += shared->start_position();
9505 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009506 }
9507 return Heap::undefined_value();
9508}
9509
9510
9511// Clear a break point
9512// args[0]: number: break point object
lrn@chromium.org303ada72010-10-27 09:33:13 +00009513static MaybeObject* Runtime_ClearBreakPoint(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009514 HandleScope scope;
9515 ASSERT(args.length() == 1);
9516 Handle<Object> break_point_object_arg = args.at<Object>(0);
9517
9518 // Clear break point.
9519 Debug::ClearBreakPoint(break_point_object_arg);
9520
9521 return Heap::undefined_value();
9522}
9523
9524
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00009525// Change the state of break on exceptions.
9526// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
9527// args[1]: Boolean indicating on/off.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009528static MaybeObject* Runtime_ChangeBreakOnException(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009529 HandleScope scope;
9530 ASSERT(args.length() == 2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00009531 RUNTIME_ASSERT(args[0]->IsNumber());
9532 CONVERT_BOOLEAN_CHECKED(enable, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009533
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00009534 // If the number doesn't match an enum value, the ChangeBreakOnException
9535 // function will default to affecting caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009536 ExceptionBreakType type =
9537 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00009538 // Update break point state.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009539 Debug::ChangeBreakOnException(type, enable);
9540 return Heap::undefined_value();
9541}
9542
9543
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00009544// Returns the state of break on exceptions
9545// args[0]: boolean indicating uncaught exceptions
lrn@chromium.org303ada72010-10-27 09:33:13 +00009546static MaybeObject* Runtime_IsBreakOnException(Arguments args) {
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00009547 HandleScope scope;
9548 ASSERT(args.length() == 1);
9549 RUNTIME_ASSERT(args[0]->IsNumber());
9550
9551 ExceptionBreakType type =
9552 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
9553 bool result = Debug::IsBreakOnException(type);
9554 return Smi::FromInt(result);
9555}
9556
9557
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009558// Prepare for stepping
9559// args[0]: break id for checking execution state
9560// args[1]: step action from the enumeration StepAction
ager@chromium.orga1645e22009-09-09 19:27:10 +00009561// args[2]: number of times to perform the step, for step out it is the number
9562// of frames to step down.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009563static MaybeObject* Runtime_PrepareStep(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009564 HandleScope scope;
9565 ASSERT(args.length() == 3);
9566 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009567 Object* check;
9568 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
9569 if (!maybe_check->ToObject(&check)) return maybe_check;
9570 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009571 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
9572 return Top::Throw(Heap::illegal_argument_symbol());
9573 }
9574
9575 // Get the step action and check validity.
9576 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
9577 if (step_action != StepIn &&
9578 step_action != StepNext &&
9579 step_action != StepOut &&
9580 step_action != StepInMin &&
9581 step_action != StepMin) {
9582 return Top::Throw(Heap::illegal_argument_symbol());
9583 }
9584
9585 // Get the number of steps.
9586 int step_count = NumberToInt32(args[2]);
9587 if (step_count < 1) {
9588 return Top::Throw(Heap::illegal_argument_symbol());
9589 }
9590
ager@chromium.orga1645e22009-09-09 19:27:10 +00009591 // Clear all current stepping setup.
9592 Debug::ClearStepping();
9593
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009594 // Prepare step.
9595 Debug::PrepareStep(static_cast<StepAction>(step_action), step_count);
9596 return Heap::undefined_value();
9597}
9598
9599
9600// Clear all stepping set by PrepareStep.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009601static MaybeObject* Runtime_ClearStepping(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009602 HandleScope scope;
mads.s.ager31e71382008-08-13 09:32:07 +00009603 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009604 Debug::ClearStepping();
9605 return Heap::undefined_value();
9606}
9607
9608
9609// Creates a copy of the with context chain. The copy of the context chain is
9610// is linked to the function context supplied.
9611static Handle<Context> CopyWithContextChain(Handle<Context> context_chain,
9612 Handle<Context> function_context) {
9613 // At the bottom of the chain. Return the function context to link to.
9614 if (context_chain->is_function_context()) {
9615 return function_context;
9616 }
9617
9618 // Recursively copy the with contexts.
9619 Handle<Context> previous(context_chain->previous());
9620 Handle<JSObject> extension(JSObject::cast(context_chain->extension()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00009621 Handle<Context> context = CopyWithContextChain(function_context, previous);
9622 return Factory::NewWithContext(context,
9623 extension,
9624 context_chain->IsCatchContext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009625}
9626
9627
9628// Helper function to find or create the arguments object for
9629// Runtime_DebugEvaluate.
9630static Handle<Object> GetArgumentsObject(JavaScriptFrame* frame,
9631 Handle<JSFunction> function,
ager@chromium.orgb5737492010-07-15 09:29:43 +00009632 Handle<SerializedScopeInfo> scope_info,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009633 const ScopeInfo<>* sinfo,
9634 Handle<Context> function_context) {
9635 // Try to find the value of 'arguments' to pass as parameter. If it is not
9636 // found (that is the debugged function does not reference 'arguments' and
9637 // does not support eval) then create an 'arguments' object.
9638 int index;
9639 if (sinfo->number_of_stack_slots() > 0) {
ager@chromium.orgb5737492010-07-15 09:29:43 +00009640 index = scope_info->StackSlotIndex(Heap::arguments_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009641 if (index != -1) {
9642 return Handle<Object>(frame->GetExpression(index));
9643 }
9644 }
9645
9646 if (sinfo->number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
ager@chromium.orgb5737492010-07-15 09:29:43 +00009647 index = scope_info->ContextSlotIndex(Heap::arguments_symbol(), NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009648 if (index != -1) {
9649 return Handle<Object>(function_context->get(index));
9650 }
9651 }
9652
9653 const int length = frame->GetProvidedParametersCount();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009654 Handle<JSObject> arguments = Factory::NewArgumentsObject(function, length);
9655 Handle<FixedArray> array = Factory::NewFixedArray(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009656
9657 AssertNoAllocation no_gc;
9658 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009659 for (int i = 0; i < length; i++) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009660 array->set(i, frame->GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009661 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009662 arguments->set_elements(*array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009663 return arguments;
9664}
9665
9666
9667// Evaluate a piece of JavaScript in the context of a stack frame for
ager@chromium.org32912102009-01-16 10:38:43 +00009668// debugging. This is accomplished by creating a new context which in its
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009669// extension part has all the parameters and locals of the function on the
9670// stack frame. A function which calls eval with the code to evaluate is then
9671// compiled in this context and called in this context. As this context
9672// replaces the context of the function on the stack frame a new (empty)
9673// function is created as well to be used as the closure for the context.
9674// This function and the context acts as replacements for the function on the
9675// stack frame presenting the same view of the values of parameters and
9676// local variables as if the piece of JavaScript was evaluated at the point
9677// where the function on the stack frame is currently stopped.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009678static MaybeObject* Runtime_DebugEvaluate(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009679 HandleScope scope;
9680
9681 // Check the execution state and decode arguments frame and source to be
9682 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009683 ASSERT(args.length() == 5);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009684 Object* check_result;
9685 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(args);
9686 if (!maybe_check_result->ToObject(&check_result)) {
9687 return maybe_check_result;
9688 }
9689 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009690 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
9691 CONVERT_ARG_CHECKED(String, source, 2);
kasper.lundbd3ec4e2008-07-09 11:06:54 +00009692 CONVERT_BOOLEAN_CHECKED(disable_break, args[3]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009693 Handle<Object> additional_context(args[4]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +00009694
9695 // Handle the processing of break.
9696 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009697
9698 // Get the frame where the debugging is performed.
9699 StackFrame::Id id = UnwrapFrameId(wrapped_id);
9700 JavaScriptFrameIterator it(id);
9701 JavaScriptFrame* frame = it.frame();
9702 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +00009703 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009704 ScopeInfo<> sinfo(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009705
9706 // Traverse the saved contexts chain to find the active context for the
9707 // selected frame.
9708 SaveContext* save = Top::save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009709 while (save != NULL && !save->below(frame)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009710 save = save->prev();
9711 }
9712 ASSERT(save != NULL);
9713 SaveContext savex;
9714 Top::set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009715
9716 // Create the (empty) function replacing the function on the stack frame for
9717 // the purpose of evaluating in the context created below. It is important
9718 // that this function does not describe any parameters and local variables
9719 // in the context. If it does then this will cause problems with the lookup
9720 // in Context::Lookup, where context slots for parameters and local variables
9721 // are looked at before the extension object.
9722 Handle<JSFunction> go_between =
9723 Factory::NewFunction(Factory::empty_string(), Factory::undefined_value());
9724 go_between->set_context(function->context());
9725#ifdef DEBUG
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009726 ScopeInfo<> go_between_sinfo(go_between->shared()->scope_info());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009727 ASSERT(go_between_sinfo.number_of_parameters() == 0);
9728 ASSERT(go_between_sinfo.number_of_context_slots() == 0);
9729#endif
9730
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009731 // Materialize the content of the local scope into a JSObject.
9732 Handle<JSObject> local_scope = MaterializeLocalScope(frame);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009733
9734 // Allocate a new context for the debug evaluation and set the extension
9735 // object build.
9736 Handle<Context> context =
9737 Factory::NewFunctionContext(Context::MIN_CONTEXT_SLOTS, go_between);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009738 context->set_extension(*local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009739 // Copy any with contexts present and chain them in front of this context.
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009740 Handle<Context> frame_context(Context::cast(frame->context()));
9741 Handle<Context> function_context(frame_context->fcontext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009742 context = CopyWithContextChain(frame_context, context);
9743
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009744 if (additional_context->IsJSObject()) {
9745 context = Factory::NewWithContext(context,
9746 Handle<JSObject>::cast(additional_context), false);
9747 }
9748
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009749 // Wrap the evaluation statement in a new function compiled in the newly
9750 // created context. The function has one parameter which has to be called
9751 // 'arguments'. This it to have access to what would have been 'arguments' in
ager@chromium.org32912102009-01-16 10:38:43 +00009752 // the function being debugged.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009753 // function(arguments,__source__) {return eval(__source__);}
9754 static const char* source_str =
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00009755 "(function(arguments,__source__){return eval(__source__);})";
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009756 static const int source_str_length = StrLength(source_str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009757 Handle<String> function_source =
9758 Factory::NewStringFromAscii(Vector<const char>(source_str,
9759 source_str_length));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009760 Handle<SharedFunctionInfo> shared =
ager@chromium.org381abbb2009-02-25 13:23:22 +00009761 Compiler::CompileEval(function_source,
9762 context,
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009763 context->IsGlobalContext());
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009764 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009765 Handle<JSFunction> compiled_function =
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009766 Factory::NewFunctionFromSharedFunctionInfo(shared, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009767
9768 // Invoke the result of the compilation to get the evaluation function.
9769 bool has_pending_exception;
9770 Handle<Object> receiver(frame->receiver());
9771 Handle<Object> evaluation_function =
9772 Execution::Call(compiled_function, receiver, 0, NULL,
9773 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00009774 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009775
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009776 Handle<Object> arguments = GetArgumentsObject(frame, function, scope_info,
9777 &sinfo, function_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009778
9779 // Invoke the evaluation function and return the result.
9780 const int argc = 2;
9781 Object** argv[argc] = { arguments.location(),
9782 Handle<Object>::cast(source).location() };
9783 Handle<Object> result =
9784 Execution::Call(Handle<JSFunction>::cast(evaluation_function), receiver,
9785 argc, argv, &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00009786 if (has_pending_exception) return Failure::Exception();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009787
9788 // Skip the global proxy as it has no properties and always delegates to the
9789 // real global object.
9790 if (result->IsJSGlobalProxy()) {
9791 result = Handle<JSObject>(JSObject::cast(result->GetPrototype()));
9792 }
9793
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009794 return *result;
9795}
9796
9797
lrn@chromium.org303ada72010-10-27 09:33:13 +00009798static MaybeObject* Runtime_DebugEvaluateGlobal(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009799 HandleScope scope;
9800
9801 // Check the execution state and decode arguments frame and source to be
9802 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009803 ASSERT(args.length() == 4);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009804 Object* check_result;
9805 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(args);
9806 if (!maybe_check_result->ToObject(&check_result)) {
9807 return maybe_check_result;
9808 }
9809 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009810 CONVERT_ARG_CHECKED(String, source, 1);
kasper.lundbd3ec4e2008-07-09 11:06:54 +00009811 CONVERT_BOOLEAN_CHECKED(disable_break, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009812 Handle<Object> additional_context(args[3]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +00009813
9814 // Handle the processing of break.
9815 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009816
9817 // Enter the top context from before the debugger was invoked.
9818 SaveContext save;
9819 SaveContext* top = &save;
9820 while (top != NULL && *top->context() == *Debug::debug_context()) {
9821 top = top->prev();
9822 }
9823 if (top != NULL) {
9824 Top::set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009825 }
9826
9827 // Get the global context now set to the top context from before the
9828 // debugger was invoked.
9829 Handle<Context> context = Top::global_context();
9830
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009831 bool is_global = true;
9832
9833 if (additional_context->IsJSObject()) {
9834 // Create a function context first, than put 'with' context on top of it.
9835 Handle<JSFunction> go_between = Factory::NewFunction(
9836 Factory::empty_string(), Factory::undefined_value());
9837 go_between->set_context(*context);
9838 context =
9839 Factory::NewFunctionContext(Context::MIN_CONTEXT_SLOTS, go_between);
9840 context->set_extension(JSObject::cast(*additional_context));
9841 is_global = false;
9842 }
9843
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009844 // Compile the source to be evaluated.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009845 Handle<SharedFunctionInfo> shared =
9846 Compiler::CompileEval(source,
9847 context,
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009848 is_global);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009849 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009850 Handle<JSFunction> compiled_function =
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009851 Handle<JSFunction>(Factory::NewFunctionFromSharedFunctionInfo(shared,
9852 context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009853
9854 // Invoke the result of the compilation to get the evaluation function.
9855 bool has_pending_exception;
9856 Handle<Object> receiver = Top::global();
9857 Handle<Object> result =
9858 Execution::Call(compiled_function, receiver, 0, NULL,
9859 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00009860 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009861 return *result;
9862}
9863
9864
lrn@chromium.org303ada72010-10-27 09:33:13 +00009865static MaybeObject* Runtime_DebugGetLoadedScripts(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009866 HandleScope scope;
mads.s.ager31e71382008-08-13 09:32:07 +00009867 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009868
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009869 // Fill the script objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +00009870 Handle<FixedArray> instances = Debug::GetLoadedScripts();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009871
9872 // Convert the script objects to proper JS objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +00009873 for (int i = 0; i < instances->length(); i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00009874 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
9875 // Get the script wrapper in a local handle before calling GetScriptWrapper,
9876 // because using
9877 // instances->set(i, *GetScriptWrapper(script))
9878 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
9879 // already have deferenced the instances handle.
9880 Handle<JSValue> wrapper = GetScriptWrapper(script);
9881 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009882 }
9883
9884 // Return result as a JS array.
9885 Handle<JSObject> result = Factory::NewJSObject(Top::array_function());
9886 Handle<JSArray>::cast(result)->SetContent(*instances);
9887 return *result;
9888}
9889
9890
9891// Helper function used by Runtime_DebugReferencedBy below.
9892static int DebugReferencedBy(JSObject* target,
9893 Object* instance_filter, int max_references,
9894 FixedArray* instances, int instances_size,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009895 JSFunction* arguments_function) {
9896 NoHandleAllocation ha;
9897 AssertNoAllocation no_alloc;
9898
9899 // Iterate the heap.
9900 int count = 0;
9901 JSObject* last = NULL;
9902 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009903 HeapObject* heap_obj = NULL;
9904 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009905 (max_references == 0 || count < max_references)) {
9906 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009907 if (heap_obj->IsJSObject()) {
9908 // Skip context extension objects and argument arrays as these are
9909 // checked in the context of functions using them.
9910 JSObject* obj = JSObject::cast(heap_obj);
iposva@chromium.org245aa852009-02-10 00:49:54 +00009911 if (obj->IsJSContextExtensionObject() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009912 obj->map()->constructor() == arguments_function) {
9913 continue;
9914 }
9915
9916 // Check if the JS object has a reference to the object looked for.
9917 if (obj->ReferencesObject(target)) {
9918 // Check instance filter if supplied. This is normally used to avoid
9919 // references from mirror objects (see Runtime_IsInPrototypeChain).
9920 if (!instance_filter->IsUndefined()) {
9921 Object* V = obj;
9922 while (true) {
9923 Object* prototype = V->GetPrototype();
9924 if (prototype->IsNull()) {
9925 break;
9926 }
9927 if (instance_filter == prototype) {
9928 obj = NULL; // Don't add this object.
9929 break;
9930 }
9931 V = prototype;
9932 }
9933 }
9934
9935 if (obj != NULL) {
9936 // Valid reference found add to instance array if supplied an update
9937 // count.
9938 if (instances != NULL && count < instances_size) {
9939 instances->set(count, obj);
9940 }
9941 last = obj;
9942 count++;
9943 }
9944 }
9945 }
9946 }
9947
9948 // Check for circular reference only. This can happen when the object is only
9949 // referenced from mirrors and has a circular reference in which case the
9950 // object is not really alive and would have been garbage collected if not
9951 // referenced from the mirror.
9952 if (count == 1 && last == target) {
9953 count = 0;
9954 }
9955
9956 // Return the number of referencing objects found.
9957 return count;
9958}
9959
9960
9961// Scan the heap for objects with direct references to an object
9962// args[0]: the object to find references to
9963// args[1]: constructor function for instances to exclude (Mirror)
9964// args[2]: the the maximum number of objects to return
lrn@chromium.org303ada72010-10-27 09:33:13 +00009965static MaybeObject* Runtime_DebugReferencedBy(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009966 ASSERT(args.length() == 3);
9967
9968 // First perform a full GC in order to avoid references from dead objects.
ager@chromium.orgab99eea2009-08-25 07:05:41 +00009969 Heap::CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009970
9971 // Check parameters.
9972 CONVERT_CHECKED(JSObject, target, args[0]);
9973 Object* instance_filter = args[1];
9974 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
9975 instance_filter->IsJSObject());
9976 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
9977 RUNTIME_ASSERT(max_references >= 0);
9978
9979 // Get the constructor function for context extension and arguments array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009980 JSObject* arguments_boilerplate =
9981 Top::context()->global_context()->arguments_boilerplate();
9982 JSFunction* arguments_function =
9983 JSFunction::cast(arguments_boilerplate->map()->constructor());
9984
9985 // Get the number of referencing objects.
9986 int count;
9987 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +00009988 NULL, 0, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009989
9990 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009991 Object* object;
9992 { MaybeObject* maybe_object = Heap::AllocateFixedArray(count);
9993 if (!maybe_object->ToObject(&object)) return maybe_object;
9994 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009995 FixedArray* instances = FixedArray::cast(object);
9996
9997 // Fill the referencing objects.
9998 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +00009999 instances, count, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010000
10001 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010002 Object* result;
10003 { MaybeObject* maybe_result = Heap::AllocateJSObject(
10004 Top::context()->global_context()->array_function());
10005 if (!maybe_result->ToObject(&result)) return maybe_result;
10006 }
10007 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010008 return result;
10009}
10010
10011
10012// Helper function used by Runtime_DebugConstructedBy below.
10013static int DebugConstructedBy(JSFunction* constructor, int max_references,
10014 FixedArray* instances, int instances_size) {
10015 AssertNoAllocation no_alloc;
10016
10017 // Iterate the heap.
10018 int count = 0;
10019 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010020 HeapObject* heap_obj = NULL;
10021 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010022 (max_references == 0 || count < max_references)) {
10023 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010024 if (heap_obj->IsJSObject()) {
10025 JSObject* obj = JSObject::cast(heap_obj);
10026 if (obj->map()->constructor() == constructor) {
10027 // Valid reference found add to instance array if supplied an update
10028 // count.
10029 if (instances != NULL && count < instances_size) {
10030 instances->set(count, obj);
10031 }
10032 count++;
10033 }
10034 }
10035 }
10036
10037 // Return the number of referencing objects found.
10038 return count;
10039}
10040
10041
10042// Scan the heap for objects constructed by a specific function.
10043// args[0]: the constructor to find instances of
10044// args[1]: the the maximum number of objects to return
lrn@chromium.org303ada72010-10-27 09:33:13 +000010045static MaybeObject* Runtime_DebugConstructedBy(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010046 ASSERT(args.length() == 2);
10047
10048 // First perform a full GC in order to avoid dead objects.
ager@chromium.orgab99eea2009-08-25 07:05:41 +000010049 Heap::CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010050
10051 // Check parameters.
10052 CONVERT_CHECKED(JSFunction, constructor, args[0]);
10053 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
10054 RUNTIME_ASSERT(max_references >= 0);
10055
10056 // Get the number of referencing objects.
10057 int count;
10058 count = DebugConstructedBy(constructor, max_references, NULL, 0);
10059
10060 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010061 Object* object;
10062 { MaybeObject* maybe_object = Heap::AllocateFixedArray(count);
10063 if (!maybe_object->ToObject(&object)) return maybe_object;
10064 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010065 FixedArray* instances = FixedArray::cast(object);
10066
10067 // Fill the referencing objects.
10068 count = DebugConstructedBy(constructor, max_references, instances, count);
10069
10070 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010071 Object* result;
10072 { MaybeObject* maybe_result = Heap::AllocateJSObject(
10073 Top::context()->global_context()->array_function());
10074 if (!maybe_result->ToObject(&result)) return maybe_result;
10075 }
10076 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010077 return result;
10078}
10079
10080
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010081// Find the effective prototype object as returned by __proto__.
10082// args[0]: the object to find the prototype for.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010083static MaybeObject* Runtime_DebugGetPrototype(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010084 ASSERT(args.length() == 1);
10085
10086 CONVERT_CHECKED(JSObject, obj, args[0]);
10087
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010088 // Use the __proto__ accessor.
10089 return Accessors::ObjectPrototype.getter(obj, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010090}
10091
10092
lrn@chromium.org303ada72010-10-27 09:33:13 +000010093static MaybeObject* Runtime_SystemBreak(Arguments args) {
mads.s.ager31e71382008-08-13 09:32:07 +000010094 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010095 CPU::DebugBreak();
10096 return Heap::undefined_value();
10097}
10098
10099
lrn@chromium.org303ada72010-10-27 09:33:13 +000010100static MaybeObject* Runtime_DebugDisassembleFunction(Arguments args) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010101#ifdef DEBUG
10102 HandleScope scope;
10103 ASSERT(args.length() == 1);
10104 // Get the function and make sure it is compiled.
10105 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010106 Handle<SharedFunctionInfo> shared(func->shared());
10107 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010108 return Failure::Exception();
10109 }
10110 func->code()->PrintLn();
10111#endif // DEBUG
10112 return Heap::undefined_value();
10113}
ager@chromium.org9085a012009-05-11 19:22:57 +000010114
10115
lrn@chromium.org303ada72010-10-27 09:33:13 +000010116static MaybeObject* Runtime_DebugDisassembleConstructor(Arguments args) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000010117#ifdef DEBUG
10118 HandleScope scope;
10119 ASSERT(args.length() == 1);
10120 // Get the function and make sure it is compiled.
10121 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010122 Handle<SharedFunctionInfo> shared(func->shared());
10123 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000010124 return Failure::Exception();
10125 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010126 shared->construct_stub()->PrintLn();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000010127#endif // DEBUG
10128 return Heap::undefined_value();
10129}
10130
10131
lrn@chromium.org303ada72010-10-27 09:33:13 +000010132static MaybeObject* Runtime_FunctionGetInferredName(Arguments args) {
ager@chromium.org9085a012009-05-11 19:22:57 +000010133 NoHandleAllocation ha;
10134 ASSERT(args.length() == 1);
10135
10136 CONVERT_CHECKED(JSFunction, f, args[0]);
10137 return f->shared()->inferred_name();
10138}
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010139
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010140
10141static int FindSharedFunctionInfosForScript(Script* script,
10142 FixedArray* buffer) {
10143 AssertNoAllocation no_allocations;
10144
10145 int counter = 0;
10146 int buffer_size = buffer->length();
10147 HeapIterator iterator;
10148 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
10149 ASSERT(obj != NULL);
10150 if (!obj->IsSharedFunctionInfo()) {
10151 continue;
10152 }
10153 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
10154 if (shared->script() != script) {
10155 continue;
10156 }
10157 if (counter < buffer_size) {
10158 buffer->set(counter, shared);
10159 }
10160 counter++;
10161 }
10162 return counter;
10163}
10164
10165// For a script finds all SharedFunctionInfo's in the heap that points
10166// to this script. Returns JSArray of SharedFunctionInfo wrapped
10167// in OpaqueReferences.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010168static MaybeObject* Runtime_LiveEditFindSharedFunctionInfosForScript(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010169 Arguments args) {
10170 ASSERT(args.length() == 1);
10171 HandleScope scope;
10172 CONVERT_CHECKED(JSValue, script_value, args[0]);
10173
10174 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
10175
10176 const int kBufferSize = 32;
10177
10178 Handle<FixedArray> array;
10179 array = Factory::NewFixedArray(kBufferSize);
10180 int number = FindSharedFunctionInfosForScript(*script, *array);
10181 if (number > kBufferSize) {
10182 array = Factory::NewFixedArray(number);
10183 FindSharedFunctionInfosForScript(*script, *array);
10184 }
10185
10186 Handle<JSArray> result = Factory::NewJSArrayWithElements(array);
10187 result->set_length(Smi::FromInt(number));
10188
10189 LiveEdit::WrapSharedFunctionInfos(result);
10190
10191 return *result;
10192}
10193
10194// For a script calculates compilation information about all its functions.
10195// The script source is explicitly specified by the second argument.
10196// The source of the actual script is not used, however it is important that
10197// all generated code keeps references to this particular instance of script.
10198// Returns a JSArray of compilation infos. The array is ordered so that
10199// each function with all its descendant is always stored in a continues range
10200// with the function itself going first. The root function is a script function.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010201static MaybeObject* Runtime_LiveEditGatherCompileInfo(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010202 ASSERT(args.length() == 2);
10203 HandleScope scope;
10204 CONVERT_CHECKED(JSValue, script, args[0]);
10205 CONVERT_ARG_CHECKED(String, source, 1);
10206 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
10207
10208 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
10209
10210 if (Top::has_pending_exception()) {
10211 return Failure::Exception();
10212 }
10213
10214 return result;
10215}
10216
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010217// Changes the source of the script to a new_source.
10218// If old_script_name is provided (i.e. is a String), also creates a copy of
10219// the script with its original source and sends notification to debugger.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010220static MaybeObject* Runtime_LiveEditReplaceScript(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010221 ASSERT(args.length() == 3);
10222 HandleScope scope;
10223 CONVERT_CHECKED(JSValue, original_script_value, args[0]);
10224 CONVERT_ARG_CHECKED(String, new_source, 1);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010225 Handle<Object> old_script_name(args[2]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010226
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010227 CONVERT_CHECKED(Script, original_script_pointer,
10228 original_script_value->value());
10229 Handle<Script> original_script(original_script_pointer);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010230
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010231 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
10232 new_source,
10233 old_script_name);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010234
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010235 if (old_script->IsScript()) {
10236 Handle<Script> script_handle(Script::cast(old_script));
10237 return *(GetScriptWrapper(script_handle));
10238 } else {
10239 return Heap::null_value();
10240 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010241}
10242
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010243
10244static MaybeObject* Runtime_LiveEditFunctionSourceUpdated(Arguments args) {
10245 ASSERT(args.length() == 1);
10246 HandleScope scope;
10247 CONVERT_ARG_CHECKED(JSArray, shared_info, 0);
10248 return LiveEdit::FunctionSourceUpdated(shared_info);
10249}
10250
10251
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010252// Replaces code of SharedFunctionInfo with a new one.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010253static MaybeObject* Runtime_LiveEditReplaceFunctionCode(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010254 ASSERT(args.length() == 2);
10255 HandleScope scope;
10256 CONVERT_ARG_CHECKED(JSArray, new_compile_info, 0);
10257 CONVERT_ARG_CHECKED(JSArray, shared_info, 1);
10258
ager@chromium.orgac091b72010-05-05 07:34:42 +000010259 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010260}
10261
10262// Connects SharedFunctionInfo to another script.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010263static MaybeObject* Runtime_LiveEditFunctionSetScript(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010264 ASSERT(args.length() == 2);
10265 HandleScope scope;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010266 Handle<Object> function_object(args[0]);
10267 Handle<Object> script_object(args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010268
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010269 if (function_object->IsJSValue()) {
10270 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
10271 if (script_object->IsJSValue()) {
10272 CONVERT_CHECKED(Script, script, JSValue::cast(*script_object)->value());
10273 script_object = Handle<Object>(script);
10274 }
10275
10276 LiveEdit::SetFunctionScript(function_wrapper, script_object);
10277 } else {
10278 // Just ignore this. We may not have a SharedFunctionInfo for some functions
10279 // and we check it in this function.
10280 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010281
10282 return Heap::undefined_value();
10283}
10284
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010285
10286// In a code of a parent function replaces original function as embedded object
10287// with a substitution one.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010288static MaybeObject* Runtime_LiveEditReplaceRefToNestedFunction(Arguments args) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010289 ASSERT(args.length() == 3);
10290 HandleScope scope;
10291
10292 CONVERT_ARG_CHECKED(JSValue, parent_wrapper, 0);
10293 CONVERT_ARG_CHECKED(JSValue, orig_wrapper, 1);
10294 CONVERT_ARG_CHECKED(JSValue, subst_wrapper, 2);
10295
10296 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
10297 subst_wrapper);
10298
10299 return Heap::undefined_value();
10300}
10301
10302
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010303// Updates positions of a shared function info (first parameter) according
10304// to script source change. Text change is described in second parameter as
10305// array of groups of 3 numbers:
10306// (change_begin, change_end, change_end_new_position).
10307// Each group describes a change in text; groups are sorted by change_begin.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010308static MaybeObject* Runtime_LiveEditPatchFunctionPositions(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010309 ASSERT(args.length() == 2);
10310 HandleScope scope;
10311 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
10312 CONVERT_ARG_CHECKED(JSArray, position_change_array, 1);
10313
ager@chromium.orgac091b72010-05-05 07:34:42 +000010314 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010315}
10316
10317
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010318// For array of SharedFunctionInfo's (each wrapped in JSValue)
10319// checks that none of them have activations on stacks (of any thread).
10320// Returns array of the same length with corresponding results of
10321// LiveEdit::FunctionPatchabilityStatus type.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010322static MaybeObject* Runtime_LiveEditCheckAndDropActivations(Arguments args) {
ager@chromium.org357bf652010-04-12 11:30:10 +000010323 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010324 HandleScope scope;
10325 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
ager@chromium.org357bf652010-04-12 11:30:10 +000010326 CONVERT_BOOLEAN_CHECKED(do_drop, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010327
ager@chromium.org357bf652010-04-12 11:30:10 +000010328 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010329}
10330
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010331// Compares 2 strings line-by-line and returns diff in form of JSArray of
fschneider@chromium.org013f3e12010-04-26 13:27:52 +000010332// triplets (pos1, pos1_end, pos2_end) describing list of diff chunks.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010333static MaybeObject* Runtime_LiveEditCompareStringsLinewise(Arguments args) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010334 ASSERT(args.length() == 2);
10335 HandleScope scope;
10336 CONVERT_ARG_CHECKED(String, s1, 0);
10337 CONVERT_ARG_CHECKED(String, s2, 1);
10338
10339 return *LiveEdit::CompareStringsLinewise(s1, s2);
10340}
10341
10342
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010343
fschneider@chromium.org086aac62010-03-17 13:18:24 +000010344// A testing entry. Returns statement position which is the closest to
10345// source_position.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010346static MaybeObject* Runtime_GetFunctionCodePositionFromSource(Arguments args) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +000010347 ASSERT(args.length() == 2);
10348 HandleScope scope;
10349 CONVERT_ARG_CHECKED(JSFunction, function, 0);
10350 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
10351
10352 Handle<Code> code(function->code());
10353
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010354 if (code->kind() != Code::FUNCTION &&
10355 code->kind() != Code::OPTIMIZED_FUNCTION) {
10356 return Heap::undefined_value();
10357 }
10358
10359 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
fschneider@chromium.org086aac62010-03-17 13:18:24 +000010360 int closest_pc = 0;
10361 int distance = kMaxInt;
10362 while (!it.done()) {
10363 int statement_position = static_cast<int>(it.rinfo()->data());
10364 // Check if this break point is closer that what was previously found.
10365 if (source_position <= statement_position &&
10366 statement_position - source_position < distance) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +000010367 closest_pc =
10368 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
fschneider@chromium.org086aac62010-03-17 13:18:24 +000010369 distance = statement_position - source_position;
10370 // Check whether we can't get any closer.
10371 if (distance == 0) break;
10372 }
10373 it.next();
10374 }
10375
10376 return Smi::FromInt(closest_pc);
10377}
10378
10379
ager@chromium.org357bf652010-04-12 11:30:10 +000010380// Calls specified function with or without entering the debugger.
10381// This is used in unit tests to run code as if debugger is entered or simply
10382// to have a stack with C++ frame in the middle.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010383static MaybeObject* Runtime_ExecuteInDebugContext(Arguments args) {
ager@chromium.org357bf652010-04-12 11:30:10 +000010384 ASSERT(args.length() == 2);
10385 HandleScope scope;
10386 CONVERT_ARG_CHECKED(JSFunction, function, 0);
10387 CONVERT_BOOLEAN_CHECKED(without_debugger, args[1]);
10388
10389 Handle<Object> result;
10390 bool pending_exception;
10391 {
10392 if (without_debugger) {
10393 result = Execution::Call(function, Top::global(), 0, NULL,
10394 &pending_exception);
10395 } else {
10396 EnterDebugger enter_debugger;
10397 result = Execution::Call(function, Top::global(), 0, NULL,
10398 &pending_exception);
10399 }
10400 }
10401 if (!pending_exception) {
10402 return *result;
10403 } else {
10404 return Failure::Exception();
10405 }
10406}
10407
10408
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010409#endif // ENABLE_DEBUGGER_SUPPORT
10410
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010411#ifdef ENABLE_LOGGING_AND_PROFILING
10412
lrn@chromium.org303ada72010-10-27 09:33:13 +000010413static MaybeObject* Runtime_ProfilerResume(Arguments args) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010414 NoHandleAllocation ha;
ager@chromium.org5c838252010-02-19 08:53:10 +000010415 ASSERT(args.length() == 2);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010416
10417 CONVERT_CHECKED(Smi, smi_modules, args[0]);
ager@chromium.org5c838252010-02-19 08:53:10 +000010418 CONVERT_CHECKED(Smi, smi_tag, args[1]);
10419 v8::V8::ResumeProfilerEx(smi_modules->value(), smi_tag->value());
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010420 return Heap::undefined_value();
10421}
10422
10423
lrn@chromium.org303ada72010-10-27 09:33:13 +000010424static MaybeObject* Runtime_ProfilerPause(Arguments args) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010425 NoHandleAllocation ha;
ager@chromium.org5c838252010-02-19 08:53:10 +000010426 ASSERT(args.length() == 2);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010427
10428 CONVERT_CHECKED(Smi, smi_modules, args[0]);
ager@chromium.org5c838252010-02-19 08:53:10 +000010429 CONVERT_CHECKED(Smi, smi_tag, args[1]);
10430 v8::V8::PauseProfilerEx(smi_modules->value(), smi_tag->value());
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010431 return Heap::undefined_value();
10432}
10433
10434#endif // ENABLE_LOGGING_AND_PROFILING
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010435
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010436// Finds the script object from the script data. NOTE: This operation uses
10437// heap traversal to find the function generated for the source position
10438// for the requested break point. For lazily compiled functions several heap
10439// traversals might be required rendering this operation as a rather slow
10440// operation. However for setting break points which is normally done through
10441// some kind of user interaction the performance is not crucial.
10442static Handle<Object> Runtime_GetScriptFromScriptName(
10443 Handle<String> script_name) {
10444 // Scan the heap for Script objects to find the script with the requested
10445 // script data.
10446 Handle<Script> script;
10447 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010448 HeapObject* obj = NULL;
10449 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010450 // If a script is found check if it has the script data requested.
10451 if (obj->IsScript()) {
10452 if (Script::cast(obj)->name()->IsString()) {
10453 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
10454 script = Handle<Script>(Script::cast(obj));
10455 }
10456 }
10457 }
10458 }
10459
10460 // If no script with the requested script data is found return undefined.
10461 if (script.is_null()) return Factory::undefined_value();
10462
10463 // Return the script found.
10464 return GetScriptWrapper(script);
10465}
10466
10467
10468// Get the script object from script data. NOTE: Regarding performance
10469// see the NOTE for GetScriptFromScriptData.
10470// args[0]: script data for the script to find the source for
lrn@chromium.org303ada72010-10-27 09:33:13 +000010471static MaybeObject* Runtime_GetScript(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010472 HandleScope scope;
10473
10474 ASSERT(args.length() == 1);
10475
10476 CONVERT_CHECKED(String, script_name, args[0]);
10477
10478 // Find the requested script.
10479 Handle<Object> result =
10480 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
10481 return *result;
10482}
10483
10484
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010485// Determines whether the given stack frame should be displayed in
10486// a stack trace. The caller is the error constructor that asked
10487// for the stack trace to be collected. The first time a construct
10488// call to this function is encountered it is skipped. The seen_caller
10489// in/out parameter is used to remember if the caller has been seen
10490// yet.
10491static bool ShowFrameInStackTrace(StackFrame* raw_frame, Object* caller,
10492 bool* seen_caller) {
10493 // Only display JS frames.
10494 if (!raw_frame->is_java_script())
10495 return false;
10496 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
10497 Object* raw_fun = frame->function();
10498 // Not sure when this can happen but skip it just in case.
10499 if (!raw_fun->IsJSFunction())
10500 return false;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010501 if ((raw_fun == caller) && !(*seen_caller)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010502 *seen_caller = true;
10503 return false;
10504 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010505 // Skip all frames until we've seen the caller. Also, skip the most
10506 // obvious builtin calls. Some builtin calls (such as Number.ADD
10507 // which is invoked using 'call') are very difficult to recognize
10508 // so we're leaving them in for now.
10509 return *seen_caller && !frame->receiver()->IsJSBuiltinsObject();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010510}
10511
10512
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010513// Collect the raw data for a stack trace. Returns an array of 4
10514// element segments each containing a receiver, function, code and
10515// native code offset.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010516static MaybeObject* Runtime_CollectStackTrace(Arguments args) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010517 ASSERT_EQ(args.length(), 2);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010518 Handle<Object> caller = args.at<Object>(0);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010519 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[1]);
10520
10521 HandleScope scope;
10522
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000010523 limit = Max(limit, 0); // Ensure that limit is not negative.
10524 int initial_size = Min(limit, 10);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010525 Handle<JSArray> result = Factory::NewJSArray(initial_size * 4);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010526
10527 StackFrameIterator iter;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010528 // If the caller parameter is a function we skip frames until we're
10529 // under it before starting to collect.
10530 bool seen_caller = !caller->IsJSFunction();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010531 int cursor = 0;
10532 int frames_seen = 0;
10533 while (!iter.done() && frames_seen < limit) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010534 StackFrame* raw_frame = iter.frame();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010535 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010536 frames_seen++;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010537 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010538 List<FrameSummary> frames(3); // Max 2 levels of inlining.
10539 frame->Summarize(&frames);
10540 for (int i = frames.length() - 1; i >= 0; i--) {
10541 Handle<Object> recv = frames[i].receiver();
10542 Handle<JSFunction> fun = frames[i].function();
10543 Handle<Code> code = frames[i].code();
10544 Handle<Smi> offset(Smi::FromInt(frames[i].offset()));
10545 FixedArray* elements = FixedArray::cast(result->elements());
10546 if (cursor + 3 < elements->length()) {
10547 elements->set(cursor++, *recv);
10548 elements->set(cursor++, *fun);
10549 elements->set(cursor++, *code);
10550 elements->set(cursor++, *offset);
10551 } else {
10552 SetElement(result, cursor++, recv);
10553 SetElement(result, cursor++, fun);
10554 SetElement(result, cursor++, code);
10555 SetElement(result, cursor++, offset);
10556 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010557 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010558 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010559 iter.Advance();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010560 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010561
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010562 result->set_length(Smi::FromInt(cursor));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010563 return *result;
10564}
10565
10566
ager@chromium.org3811b432009-10-28 14:53:37 +000010567// Returns V8 version as a string.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010568static MaybeObject* Runtime_GetV8Version(Arguments args) {
ager@chromium.org3811b432009-10-28 14:53:37 +000010569 ASSERT_EQ(args.length(), 0);
10570
10571 NoHandleAllocation ha;
10572
10573 const char* version_string = v8::V8::GetVersion();
10574
10575 return Heap::AllocateStringFromAscii(CStrVector(version_string), NOT_TENURED);
10576}
10577
10578
lrn@chromium.org303ada72010-10-27 09:33:13 +000010579static MaybeObject* Runtime_Abort(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010580 ASSERT(args.length() == 2);
10581 OS::PrintError("abort: %s\n", reinterpret_cast<char*>(args[0]) +
10582 Smi::cast(args[1])->value());
10583 Top::PrintStack();
10584 OS::Abort();
10585 UNREACHABLE();
10586 return NULL;
10587}
10588
10589
lrn@chromium.org303ada72010-10-27 09:33:13 +000010590MUST_USE_RESULT static MaybeObject* CacheMiss(FixedArray* cache_obj,
10591 int index,
10592 Object* key_obj) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010593 ASSERT(index % 2 == 0); // index of the key
10594 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
10595 ASSERT(index < cache_obj->length());
10596
10597 HandleScope scope;
10598
10599 Handle<FixedArray> cache(cache_obj);
10600 Handle<Object> key(key_obj);
10601 Handle<JSFunction> factory(JSFunction::cast(
10602 cache->get(JSFunctionResultCache::kFactoryIndex)));
10603 // TODO(antonm): consider passing a receiver when constructing a cache.
10604 Handle<Object> receiver(Top::global_context()->global());
10605
10606 Handle<Object> value;
10607 {
10608 // This handle is nor shared, nor used later, so it's safe.
10609 Object** argv[] = { key.location() };
10610 bool pending_exception = false;
10611 value = Execution::Call(factory,
10612 receiver,
10613 1,
10614 argv,
10615 &pending_exception);
10616 if (pending_exception) return Failure::Exception();
10617 }
10618
10619 cache->set(index, *key);
10620 cache->set(index + 1, *value);
10621 cache->set(JSFunctionResultCache::kFingerIndex, Smi::FromInt(index));
10622
10623 return *value;
10624}
10625
10626
lrn@chromium.org303ada72010-10-27 09:33:13 +000010627static MaybeObject* Runtime_GetFromCache(Arguments args) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010628 // This is only called from codegen, so checks might be more lax.
10629 CONVERT_CHECKED(FixedArray, cache, args[0]);
10630 Object* key = args[1];
10631
10632 const int finger_index =
10633 Smi::cast(cache->get(JSFunctionResultCache::kFingerIndex))->value();
10634
10635 Object* o = cache->get(finger_index);
10636 if (o == key) {
10637 // The fastest case: hit the same place again.
10638 return cache->get(finger_index + 1);
10639 }
10640
10641 for (int i = finger_index - 2;
10642 i >= JSFunctionResultCache::kEntriesIndex;
10643 i -= 2) {
10644 o = cache->get(i);
10645 if (o == key) {
10646 cache->set(JSFunctionResultCache::kFingerIndex, Smi::FromInt(i));
10647 return cache->get(i + 1);
10648 }
10649 }
10650
10651 const int size =
10652 Smi::cast(cache->get(JSFunctionResultCache::kCacheSizeIndex))->value();
10653 ASSERT(size <= cache->length());
10654
10655 for (int i = size - 2; i > finger_index; i -= 2) {
10656 o = cache->get(i);
10657 if (o == key) {
10658 cache->set(JSFunctionResultCache::kFingerIndex, Smi::FromInt(i));
10659 return cache->get(i + 1);
10660 }
10661 }
10662
10663 // Cache miss. If we have spare room, put new data into it, otherwise
10664 // evict post finger entry which must be least recently used.
10665 if (size < cache->length()) {
10666 cache->set(JSFunctionResultCache::kCacheSizeIndex, Smi::FromInt(size + 2));
10667 return CacheMiss(cache, size, key);
10668 } else {
antonm@chromium.org397e23c2010-04-21 12:00:05 +000010669 int target_index = finger_index + JSFunctionResultCache::kEntrySize;
10670 if (target_index == cache->length()) {
10671 target_index = JSFunctionResultCache::kEntriesIndex;
10672 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010673 return CacheMiss(cache, target_index, key);
10674 }
10675}
10676
kasper.lund44510672008-07-25 07:37:58 +000010677#ifdef DEBUG
10678// ListNatives is ONLY used by the fuzz-natives.js in debug mode
10679// Exclude the code in release mode.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010680static MaybeObject* Runtime_ListNatives(Arguments args) {
mads.s.ager31e71382008-08-13 09:32:07 +000010681 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010682 HandleScope scope;
10683 Handle<JSArray> result = Factory::NewJSArray(0);
10684 int index = 0;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000010685 bool inline_runtime_functions = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +000010686#define ADD_ENTRY(Name, argc, ressize) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010687 { \
10688 HandleScope inner; \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000010689 Handle<String> name; \
10690 /* Inline runtime functions have an underscore in front of the name. */ \
10691 if (inline_runtime_functions) { \
10692 name = Factory::NewStringFromAscii( \
10693 Vector<const char>("_" #Name, StrLength("_" #Name))); \
10694 } else { \
10695 name = Factory::NewStringFromAscii( \
10696 Vector<const char>(#Name, StrLength(#Name))); \
10697 } \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010698 Handle<JSArray> pair = Factory::NewJSArray(0); \
10699 SetElement(pair, 0, name); \
10700 SetElement(pair, 1, Handle<Smi>(Smi::FromInt(argc))); \
10701 SetElement(result, index++, pair); \
10702 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000010703 inline_runtime_functions = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010704 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000010705 inline_runtime_functions = true;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010706 INLINE_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000010707 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010708#undef ADD_ENTRY
10709 return *result;
10710}
kasper.lund44510672008-07-25 07:37:58 +000010711#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010712
10713
lrn@chromium.org303ada72010-10-27 09:33:13 +000010714static MaybeObject* Runtime_Log(Arguments args) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000010715 ASSERT(args.length() == 2);
ager@chromium.org381abbb2009-02-25 13:23:22 +000010716 CONVERT_CHECKED(String, format, args[0]);
10717 CONVERT_CHECKED(JSArray, elms, args[1]);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000010718 Vector<const char> chars = format->ToAsciiVector();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000010719 Logger::LogRuntime(chars, elms);
10720 return Heap::undefined_value();
10721}
10722
10723
lrn@chromium.org303ada72010-10-27 09:33:13 +000010724static MaybeObject* Runtime_IS_VAR(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010725 UNREACHABLE(); // implemented as macro in the parser
10726 return NULL;
10727}
10728
10729
10730// ----------------------------------------------------------------------------
10731// Implementation of Runtime
10732
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010733#define F(name, number_of_args, result_size) \
10734 { Runtime::k##name, Runtime::RUNTIME, #name, \
10735 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010736
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010737
10738#define I(name, number_of_args, result_size) \
10739 { Runtime::kInline##name, Runtime::INLINE, \
10740 "_" #name, NULL, number_of_args, result_size },
10741
10742Runtime::Function kIntrinsicFunctions[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010743 RUNTIME_FUNCTION_LIST(F)
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010744 INLINE_FUNCTION_LIST(I)
10745 INLINE_RUNTIME_FUNCTION_LIST(I)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010746};
10747
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010748
lrn@chromium.org303ada72010-10-27 09:33:13 +000010749MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Object* dictionary) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010750 ASSERT(dictionary != NULL);
10751 ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
10752 for (int i = 0; i < kNumFunctions; ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000010753 Object* name_symbol;
10754 { MaybeObject* maybe_name_symbol =
10755 Heap::LookupAsciiSymbol(kIntrinsicFunctions[i].name);
10756 if (!maybe_name_symbol->ToObject(&name_symbol)) return maybe_name_symbol;
10757 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010758 StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010759 { MaybeObject* maybe_dictionary = string_dictionary->Add(
10760 String::cast(name_symbol),
10761 Smi::FromInt(i),
10762 PropertyDetails(NONE, NORMAL));
10763 if (!maybe_dictionary->ToObject(&dictionary)) {
10764 // Non-recoverable failure. Calling code must restart heap
10765 // initialization.
10766 return maybe_dictionary;
10767 }
10768 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010769 }
10770 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010771}
10772
10773
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010774Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
10775 int entry = Heap::intrinsic_function_names()->FindEntry(*name);
10776 if (entry != kNotFound) {
10777 Object* smi_index = Heap::intrinsic_function_names()->ValueAt(entry);
10778 int function_index = Smi::cast(smi_index)->value();
10779 return &(kIntrinsicFunctions[function_index]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010780 }
10781 return NULL;
10782}
10783
10784
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010785Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
10786 return &(kIntrinsicFunctions[static_cast<int>(id)]);
10787}
10788
10789
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010790void Runtime::PerformGC(Object* result) {
10791 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010792 if (failure->IsRetryAfterGC()) {
10793 // Try to do a garbage collection; ignore it if it fails. The C
10794 // entry stub will throw an out-of-memory exception in that case.
whesse@chromium.org4a5224e2010-10-20 12:37:07 +000010795 Heap::CollectGarbage(failure->allocation_space());
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010796 } else {
10797 // Handle last resort GC and make sure to allow future allocations
10798 // to grow the heap without causing GCs (if possible).
10799 Counters::gc_last_resort_from_js.Increment();
ager@chromium.orgab99eea2009-08-25 07:05:41 +000010800 Heap::CollectAllGarbage(false);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010801 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010802}
10803
10804
10805} } // namespace v8::internal