blob: 5a443efc3d0fb9b0445b50cf50a22f9472da78f9 [file] [log] [blame]
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001// Copyright 2010 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include <stdlib.h>
29
30#include "v8.h"
31
32#include "accessors.h"
33#include "api.h"
34#include "arguments.h"
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000035#include "codegen.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000036#include "compilation-cache.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000037#include "compiler.h"
38#include "cpu.h"
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000039#include "dateparser-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000040#include "debug.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000041#include "deoptimizer.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000042#include "execution.h"
43#include "jsregexp.h"
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000044#include "liveedit.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000045#include "parser.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000046#include "platform.h"
47#include "runtime.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000048#include "runtime-profiler.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000049#include "scopeinfo.h"
ager@chromium.org7c537e22008-10-16 08:43:32 +000050#include "smart-pointer.h"
ager@chromium.org18ad94b2009-09-02 08:22:29 +000051#include "stub-cache.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000052#include "v8threads.h"
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000053#include "string-search.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000054
kasperl@chromium.org71affb52009-05-26 05:44:31 +000055namespace v8 {
56namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000057
58
ager@chromium.org3e875802009-06-29 08:26:34 +000059#define RUNTIME_ASSERT(value) \
60 if (!(value)) return Top::ThrowIllegalOperation();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000061
62// Cast the given object to a value of the specified type and store
63// it in a variable with the given name. If the object is not of the
64// expected type call IllegalOperation and return.
65#define CONVERT_CHECKED(Type, name, obj) \
66 RUNTIME_ASSERT(obj->Is##Type()); \
67 Type* name = Type::cast(obj);
68
69#define CONVERT_ARG_CHECKED(Type, name, index) \
70 RUNTIME_ASSERT(args[index]->Is##Type()); \
71 Handle<Type> name = args.at<Type>(index);
72
kasper.lundbd3ec4e2008-07-09 11:06:54 +000073// Cast the given object to a boolean and store it in a variable with
74// the given name. If the object is not a boolean call IllegalOperation
75// and return.
76#define CONVERT_BOOLEAN_CHECKED(name, obj) \
77 RUNTIME_ASSERT(obj->IsBoolean()); \
78 bool name = (obj)->IsTrue();
79
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000080// Cast the given object to a Smi and store its value in an int variable
81// with the given name. If the object is not a Smi call IllegalOperation
82// and return.
83#define CONVERT_SMI_CHECKED(name, obj) \
84 RUNTIME_ASSERT(obj->IsSmi()); \
85 int name = Smi::cast(obj)->value();
86
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000087// Cast the given object to a double and store it in a variable with
88// the given name. If the object is not a number (as opposed to
89// the number not-a-number) call IllegalOperation and return.
90#define CONVERT_DOUBLE_CHECKED(name, obj) \
91 RUNTIME_ASSERT(obj->IsNumber()); \
92 double name = (obj)->Number();
93
94// Call the specified converter on the object *comand store the result in
95// a variable of the specified type with the given name. If the
96// object is not a Number call IllegalOperation and return.
97#define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \
98 RUNTIME_ASSERT(obj->IsNumber()); \
99 type name = NumberTo##Type(obj);
100
101// Non-reentrant string buffer for efficient general use in this file.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000102static StaticResource<StringInputBuffer> runtime_string_input_buffer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000103
104
lrn@chromium.org303ada72010-10-27 09:33:13 +0000105MUST_USE_RESULT static MaybeObject* DeepCopyBoilerplate(JSObject* boilerplate) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000106 StackLimitCheck check;
107 if (check.HasOverflowed()) return Top::StackOverflow();
108
lrn@chromium.org303ada72010-10-27 09:33:13 +0000109 Object* result;
110 { MaybeObject* maybe_result = Heap::CopyJSObject(boilerplate);
111 if (!maybe_result->ToObject(&result)) return maybe_result;
112 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000113 JSObject* copy = JSObject::cast(result);
114
115 // Deep copy local properties.
116 if (copy->HasFastProperties()) {
117 FixedArray* properties = copy->properties();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000118 for (int i = 0; i < properties->length(); i++) {
119 Object* value = properties->get(i);
120 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000121 JSObject* js_object = JSObject::cast(value);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000122 { MaybeObject* maybe_result = DeepCopyBoilerplate(js_object);
123 if (!maybe_result->ToObject(&result)) return maybe_result;
124 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000125 properties->set(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000126 }
127 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000128 int nof = copy->map()->inobject_properties();
129 for (int i = 0; i < nof; i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000130 Object* value = copy->InObjectPropertyAt(i);
131 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000132 JSObject* js_object = JSObject::cast(value);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000133 { MaybeObject* maybe_result = DeepCopyBoilerplate(js_object);
134 if (!maybe_result->ToObject(&result)) return maybe_result;
135 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000136 copy->InObjectPropertyAtPut(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000137 }
138 }
139 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000140 { MaybeObject* maybe_result =
141 Heap::AllocateFixedArray(copy->NumberOfLocalProperties(NONE));
142 if (!maybe_result->ToObject(&result)) return maybe_result;
143 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000144 FixedArray* names = FixedArray::cast(result);
145 copy->GetLocalPropertyNames(names, 0);
146 for (int i = 0; i < names->length(); i++) {
147 ASSERT(names->get(i)->IsString());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000148 String* key_string = String::cast(names->get(i));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000149 PropertyAttributes attributes =
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000150 copy->GetLocalPropertyAttribute(key_string);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000151 // Only deep copy fields from the object literal expression.
152 // In particular, don't try to copy the length attribute of
153 // an array.
154 if (attributes != NONE) continue;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000155 Object* value =
156 copy->GetProperty(key_string, &attributes)->ToObjectUnchecked();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000157 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000158 JSObject* js_object = JSObject::cast(value);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000159 { MaybeObject* maybe_result = DeepCopyBoilerplate(js_object);
160 if (!maybe_result->ToObject(&result)) return maybe_result;
161 }
162 { MaybeObject* maybe_result =
163 copy->SetProperty(key_string, result, NONE);
164 if (!maybe_result->ToObject(&result)) return maybe_result;
165 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000166 }
167 }
168 }
169
170 // Deep copy local elements.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000171 // Pixel elements cannot be created using an object literal.
ager@chromium.org3811b432009-10-28 14:53:37 +0000172 ASSERT(!copy->HasPixelElements() && !copy->HasExternalArrayElements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000173 switch (copy->GetElementsKind()) {
174 case JSObject::FAST_ELEMENTS: {
175 FixedArray* elements = FixedArray::cast(copy->elements());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000176 if (elements->map() == Heap::fixed_cow_array_map()) {
177 Counters::cow_arrays_created_runtime.Increment();
178#ifdef DEBUG
179 for (int i = 0; i < elements->length(); i++) {
180 ASSERT(!elements->get(i)->IsJSObject());
181 }
182#endif
183 } else {
184 for (int i = 0; i < elements->length(); i++) {
185 Object* value = elements->get(i);
186 if (value->IsJSObject()) {
187 JSObject* js_object = JSObject::cast(value);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000188 { MaybeObject* maybe_result = DeepCopyBoilerplate(js_object);
189 if (!maybe_result->ToObject(&result)) return maybe_result;
190 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000191 elements->set(i, result);
192 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000193 }
194 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000195 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000196 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000197 case JSObject::DICTIONARY_ELEMENTS: {
198 NumberDictionary* element_dictionary = copy->element_dictionary();
199 int capacity = element_dictionary->Capacity();
200 for (int i = 0; i < capacity; i++) {
201 Object* k = element_dictionary->KeyAt(i);
202 if (element_dictionary->IsKey(k)) {
203 Object* value = element_dictionary->ValueAt(i);
204 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000205 JSObject* js_object = JSObject::cast(value);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000206 { MaybeObject* maybe_result = DeepCopyBoilerplate(js_object);
207 if (!maybe_result->ToObject(&result)) return maybe_result;
208 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000209 element_dictionary->ValueAtPut(i, result);
210 }
211 }
212 }
213 break;
214 }
215 default:
216 UNREACHABLE();
217 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000218 }
219 return copy;
220}
221
222
lrn@chromium.org303ada72010-10-27 09:33:13 +0000223static MaybeObject* Runtime_CloneLiteralBoilerplate(Arguments args) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000224 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
225 return DeepCopyBoilerplate(boilerplate);
226}
227
228
lrn@chromium.org303ada72010-10-27 09:33:13 +0000229static MaybeObject* Runtime_CloneShallowLiteralBoilerplate(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000230 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000231 return Heap::CopyJSObject(boilerplate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000232}
233
234
ager@chromium.org236ad962008-09-25 09:45:57 +0000235static Handle<Map> ComputeObjectLiteralMap(
236 Handle<Context> context,
237 Handle<FixedArray> constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000238 bool* is_result_from_cache) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000239 int properties_length = constant_properties->length();
240 int number_of_properties = properties_length / 2;
ager@chromium.org236ad962008-09-25 09:45:57 +0000241 if (FLAG_canonicalize_object_literal_maps) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000242 // Check that there are only symbols and array indices among keys.
ager@chromium.org236ad962008-09-25 09:45:57 +0000243 int number_of_symbol_keys = 0;
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000244 for (int p = 0; p != properties_length; p += 2) {
245 Object* key = constant_properties->get(p);
246 uint32_t element_index = 0;
247 if (key->IsSymbol()) {
248 number_of_symbol_keys++;
249 } else if (key->ToArrayIndex(&element_index)) {
250 // An index key does not require space in the property backing store.
251 number_of_properties--;
252 } else {
253 // Bail out as a non-symbol non-index key makes caching impossible.
254 // ASSERT to make sure that the if condition after the loop is false.
255 ASSERT(number_of_symbol_keys != number_of_properties);
256 break;
257 }
ager@chromium.org236ad962008-09-25 09:45:57 +0000258 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000259 // If we only have symbols and array indices among keys then we can
260 // use the map cache in the global context.
ager@chromium.org236ad962008-09-25 09:45:57 +0000261 const int kMaxKeys = 10;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000262 if ((number_of_symbol_keys == number_of_properties) &&
263 (number_of_symbol_keys < kMaxKeys)) {
ager@chromium.org236ad962008-09-25 09:45:57 +0000264 // Create the fixed array with the key.
265 Handle<FixedArray> keys = Factory::NewFixedArray(number_of_symbol_keys);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000266 if (number_of_symbol_keys > 0) {
267 int index = 0;
268 for (int p = 0; p < properties_length; p += 2) {
269 Object* key = constant_properties->get(p);
270 if (key->IsSymbol()) {
271 keys->set(index++, key);
272 }
273 }
274 ASSERT(index == number_of_symbol_keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000275 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000276 *is_result_from_cache = true;
ager@chromium.org236ad962008-09-25 09:45:57 +0000277 return Factory::ObjectLiteralMapFromCache(context, keys);
278 }
279 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000280 *is_result_from_cache = false;
ager@chromium.org32912102009-01-16 10:38:43 +0000281 return Factory::CopyMap(
282 Handle<Map>(context->object_function()->initial_map()),
283 number_of_properties);
ager@chromium.org236ad962008-09-25 09:45:57 +0000284}
285
286
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000287static Handle<Object> CreateLiteralBoilerplate(
288 Handle<FixedArray> literals,
289 Handle<FixedArray> constant_properties);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000290
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000291
292static Handle<Object> CreateObjectLiteralBoilerplate(
293 Handle<FixedArray> literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000294 Handle<FixedArray> constant_properties,
295 bool should_have_fast_elements) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000296 // Get the global context from the literals array. This is the
297 // context in which the function was created and we use the object
298 // function from this context to create the object literal. We do
299 // not use the object function from the current global context
300 // because this might be the object function from another context
301 // which we should not have access to.
ager@chromium.org236ad962008-09-25 09:45:57 +0000302 Handle<Context> context =
303 Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals));
304
305 bool is_result_from_cache;
306 Handle<Map> map = ComputeObjectLiteralMap(context,
307 constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000308 &is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000309
ager@chromium.org236ad962008-09-25 09:45:57 +0000310 Handle<JSObject> boilerplate = Factory::NewJSObjectFromMap(map);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000311
312 // Normalize the elements of the boilerplate to save space if needed.
313 if (!should_have_fast_elements) NormalizeElements(boilerplate);
314
ager@chromium.org32912102009-01-16 10:38:43 +0000315 { // Add the constant properties to the boilerplate.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000316 int length = constant_properties->length();
ager@chromium.org236ad962008-09-25 09:45:57 +0000317 OptimizedObjectForAddingMultipleProperties opt(boilerplate,
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000318 length / 2,
ager@chromium.org236ad962008-09-25 09:45:57 +0000319 !is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000320 for (int index = 0; index < length; index +=2) {
321 Handle<Object> key(constant_properties->get(index+0));
322 Handle<Object> value(constant_properties->get(index+1));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000323 if (value->IsFixedArray()) {
324 // The value contains the constant_properties of a
325 // simple object literal.
326 Handle<FixedArray> array = Handle<FixedArray>::cast(value);
327 value = CreateLiteralBoilerplate(literals, array);
328 if (value.is_null()) return value;
329 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000330 Handle<Object> result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000331 uint32_t element_index = 0;
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000332 if (key->IsSymbol()) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000333 if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) {
334 // Array index as string (uint32).
335 result = SetOwnElement(boilerplate, element_index, value);
336 } else {
337 Handle<String> name(String::cast(*key));
338 ASSERT(!name->AsArrayIndex(&element_index));
339 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
340 value, NONE);
341 }
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000342 } else if (key->ToArrayIndex(&element_index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000343 // Array index (uint32).
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000344 result = SetOwnElement(boilerplate, element_index, value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000345 } else {
346 // Non-uint32 number.
347 ASSERT(key->IsNumber());
348 double num = key->Number();
349 char arr[100];
350 Vector<char> buffer(arr, ARRAY_SIZE(arr));
351 const char* str = DoubleToCString(num, buffer);
352 Handle<String> name = Factory::NewStringFromAscii(CStrVector(str));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000353 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
354 value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000355 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000356 // If setting the property on the boilerplate throws an
357 // exception, the exception is converted to an empty handle in
358 // the handle based operations. In that case, we need to
359 // convert back to an exception.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000360 if (result.is_null()) return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000361 }
362 }
363
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000364 return boilerplate;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000365}
366
367
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000368static Handle<Object> CreateArrayLiteralBoilerplate(
369 Handle<FixedArray> literals,
370 Handle<FixedArray> elements) {
371 // Create the JSArray.
372 Handle<JSFunction> constructor(
373 JSFunction::GlobalContextFromLiterals(*literals)->array_function());
374 Handle<Object> object = Factory::NewJSObject(constructor);
375
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000376 const bool is_cow = (elements->map() == Heap::fixed_cow_array_map());
377 Handle<FixedArray> copied_elements =
378 is_cow ? elements : Factory::CopyFixedArray(elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000379
380 Handle<FixedArray> content = Handle<FixedArray>::cast(copied_elements);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000381 if (is_cow) {
382#ifdef DEBUG
383 // Copy-on-write arrays must be shallow (and simple).
384 for (int i = 0; i < content->length(); i++) {
385 ASSERT(!content->get(i)->IsFixedArray());
386 }
387#endif
388 } else {
389 for (int i = 0; i < content->length(); i++) {
390 if (content->get(i)->IsFixedArray()) {
391 // The value contains the constant_properties of a
392 // simple object literal.
393 Handle<FixedArray> fa(FixedArray::cast(content->get(i)));
394 Handle<Object> result =
395 CreateLiteralBoilerplate(literals, fa);
396 if (result.is_null()) return result;
397 content->set(i, *result);
398 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000399 }
400 }
401
402 // Set the elements.
403 Handle<JSArray>::cast(object)->SetContent(*content);
404 return object;
405}
406
407
408static Handle<Object> CreateLiteralBoilerplate(
409 Handle<FixedArray> literals,
410 Handle<FixedArray> array) {
411 Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
412 switch (CompileTimeValue::GetType(array)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000413 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
414 return CreateObjectLiteralBoilerplate(literals, elements, true);
415 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
416 return CreateObjectLiteralBoilerplate(literals, elements, false);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000417 case CompileTimeValue::ARRAY_LITERAL:
418 return CreateArrayLiteralBoilerplate(literals, elements);
419 default:
420 UNREACHABLE();
421 return Handle<Object>::null();
422 }
423}
424
425
lrn@chromium.org303ada72010-10-27 09:33:13 +0000426static MaybeObject* Runtime_CreateArrayLiteralBoilerplate(Arguments args) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000427 // Takes a FixedArray of elements containing the literal elements of
428 // the array literal and produces JSArray with those elements.
429 // Additionally takes the literals array of the surrounding function
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000430 // which contains the context from which to get the Array function
431 // to use for creating the array literal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000432 HandleScope scope;
433 ASSERT(args.length() == 3);
434 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
435 CONVERT_SMI_CHECKED(literals_index, args[1]);
436 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000437
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000438 Handle<Object> object = CreateArrayLiteralBoilerplate(literals, elements);
439 if (object.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000440
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000441 // Update the functions literal and return the boilerplate.
442 literals->set(literals_index, *object);
443 return *object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000444}
445
446
lrn@chromium.org303ada72010-10-27 09:33:13 +0000447static MaybeObject* Runtime_CreateObjectLiteral(Arguments args) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000448 HandleScope scope;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000449 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000450 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
451 CONVERT_SMI_CHECKED(literals_index, args[1]);
452 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000453 CONVERT_SMI_CHECKED(fast_elements, args[3]);
454 bool should_have_fast_elements = fast_elements == 1;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000455
456 // Check if boilerplate exists. If not, create it first.
457 Handle<Object> boilerplate(literals->get(literals_index));
458 if (*boilerplate == Heap::undefined_value()) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000459 boilerplate = CreateObjectLiteralBoilerplate(literals,
460 constant_properties,
461 should_have_fast_elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000462 if (boilerplate.is_null()) return Failure::Exception();
463 // Update the functions literal and return the boilerplate.
464 literals->set(literals_index, *boilerplate);
465 }
466 return DeepCopyBoilerplate(JSObject::cast(*boilerplate));
467}
468
469
lrn@chromium.org303ada72010-10-27 09:33:13 +0000470static MaybeObject* Runtime_CreateObjectLiteralShallow(Arguments args) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000471 HandleScope scope;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000472 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000473 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
474 CONVERT_SMI_CHECKED(literals_index, args[1]);
475 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000476 CONVERT_SMI_CHECKED(fast_elements, args[3]);
477 bool should_have_fast_elements = fast_elements == 1;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000478
479 // Check if boilerplate exists. If not, create it first.
480 Handle<Object> boilerplate(literals->get(literals_index));
481 if (*boilerplate == Heap::undefined_value()) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000482 boilerplate = CreateObjectLiteralBoilerplate(literals,
483 constant_properties,
484 should_have_fast_elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000485 if (boilerplate.is_null()) return Failure::Exception();
486 // Update the functions literal and return the boilerplate.
487 literals->set(literals_index, *boilerplate);
488 }
489 return Heap::CopyJSObject(JSObject::cast(*boilerplate));
490}
491
492
lrn@chromium.org303ada72010-10-27 09:33:13 +0000493static MaybeObject* Runtime_CreateArrayLiteral(Arguments args) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000494 HandleScope scope;
495 ASSERT(args.length() == 3);
496 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
497 CONVERT_SMI_CHECKED(literals_index, args[1]);
498 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
499
500 // Check if boilerplate exists. If not, create it first.
501 Handle<Object> boilerplate(literals->get(literals_index));
502 if (*boilerplate == Heap::undefined_value()) {
503 boilerplate = CreateArrayLiteralBoilerplate(literals, elements);
504 if (boilerplate.is_null()) return Failure::Exception();
505 // Update the functions literal and return the boilerplate.
506 literals->set(literals_index, *boilerplate);
507 }
508 return DeepCopyBoilerplate(JSObject::cast(*boilerplate));
509}
510
511
lrn@chromium.org303ada72010-10-27 09:33:13 +0000512static MaybeObject* Runtime_CreateArrayLiteralShallow(Arguments args) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000513 HandleScope scope;
514 ASSERT(args.length() == 3);
515 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
516 CONVERT_SMI_CHECKED(literals_index, args[1]);
517 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
518
519 // Check if boilerplate exists. If not, create it first.
520 Handle<Object> boilerplate(literals->get(literals_index));
521 if (*boilerplate == Heap::undefined_value()) {
522 boilerplate = CreateArrayLiteralBoilerplate(literals, elements);
523 if (boilerplate.is_null()) return Failure::Exception();
524 // Update the functions literal and return the boilerplate.
525 literals->set(literals_index, *boilerplate);
526 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000527 if (JSObject::cast(*boilerplate)->elements()->map() ==
528 Heap::fixed_cow_array_map()) {
529 Counters::cow_arrays_created_runtime.Increment();
530 }
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000531 return Heap::CopyJSObject(JSObject::cast(*boilerplate));
532}
533
534
lrn@chromium.org303ada72010-10-27 09:33:13 +0000535static MaybeObject* Runtime_CreateCatchExtensionObject(Arguments args) {
ager@chromium.org32912102009-01-16 10:38:43 +0000536 ASSERT(args.length() == 2);
537 CONVERT_CHECKED(String, key, args[0]);
538 Object* value = args[1];
539 // Create a catch context extension object.
540 JSFunction* constructor =
541 Top::context()->global_context()->context_extension_function();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000542 Object* object;
543 { MaybeObject* maybe_object = Heap::AllocateJSObject(constructor);
544 if (!maybe_object->ToObject(&object)) return maybe_object;
545 }
ager@chromium.org32912102009-01-16 10:38:43 +0000546 // Assign the exception value to the catch variable and make sure
547 // that the catch variable is DontDelete.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000548 { MaybeObject* maybe_value =
549 JSObject::cast(object)->SetProperty(key, value, DONT_DELETE);
550 if (!maybe_value->ToObject(&value)) return maybe_value;
551 }
ager@chromium.org32912102009-01-16 10:38:43 +0000552 return object;
553}
554
555
lrn@chromium.org303ada72010-10-27 09:33:13 +0000556static MaybeObject* Runtime_ClassOf(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000557 NoHandleAllocation ha;
558 ASSERT(args.length() == 1);
559 Object* obj = args[0];
560 if (!obj->IsJSObject()) return Heap::null_value();
561 return JSObject::cast(obj)->class_name();
562}
563
ager@chromium.org7c537e22008-10-16 08:43:32 +0000564
lrn@chromium.org303ada72010-10-27 09:33:13 +0000565static MaybeObject* Runtime_IsInPrototypeChain(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000566 NoHandleAllocation ha;
567 ASSERT(args.length() == 2);
568 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
569 Object* O = args[0];
570 Object* V = args[1];
571 while (true) {
572 Object* prototype = V->GetPrototype();
573 if (prototype->IsNull()) return Heap::false_value();
574 if (O == prototype) return Heap::true_value();
575 V = prototype;
576 }
577}
578
579
ager@chromium.org9085a012009-05-11 19:22:57 +0000580// Inserts an object as the hidden prototype of another object.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000581static MaybeObject* Runtime_SetHiddenPrototype(Arguments args) {
ager@chromium.org9085a012009-05-11 19:22:57 +0000582 NoHandleAllocation ha;
583 ASSERT(args.length() == 2);
584 CONVERT_CHECKED(JSObject, jsobject, args[0]);
585 CONVERT_CHECKED(JSObject, proto, args[1]);
586
587 // Sanity checks. The old prototype (that we are replacing) could
588 // theoretically be null, but if it is not null then check that we
589 // didn't already install a hidden prototype here.
590 RUNTIME_ASSERT(!jsobject->GetPrototype()->IsHeapObject() ||
591 !HeapObject::cast(jsobject->GetPrototype())->map()->is_hidden_prototype());
592 RUNTIME_ASSERT(!proto->map()->is_hidden_prototype());
593
594 // Allocate up front before we start altering state in case we get a GC.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000595 Object* map_or_failure;
596 { MaybeObject* maybe_map_or_failure = proto->map()->CopyDropTransitions();
597 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
598 return maybe_map_or_failure;
599 }
600 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000601 Map* new_proto_map = Map::cast(map_or_failure);
602
lrn@chromium.org303ada72010-10-27 09:33:13 +0000603 { MaybeObject* maybe_map_or_failure = jsobject->map()->CopyDropTransitions();
604 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
605 return maybe_map_or_failure;
606 }
607 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000608 Map* new_map = Map::cast(map_or_failure);
609
610 // Set proto's prototype to be the old prototype of the object.
611 new_proto_map->set_prototype(jsobject->GetPrototype());
612 proto->set_map(new_proto_map);
613 new_proto_map->set_is_hidden_prototype();
614
615 // Set the object's prototype to proto.
616 new_map->set_prototype(proto);
617 jsobject->set_map(new_map);
618
619 return Heap::undefined_value();
620}
621
622
lrn@chromium.org303ada72010-10-27 09:33:13 +0000623static MaybeObject* Runtime_IsConstructCall(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000624 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +0000625 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000626 JavaScriptFrameIterator it;
627 return Heap::ToBoolean(it.frame()->IsConstructor());
628}
629
630
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000631// Recursively traverses hidden prototypes if property is not found
632static void GetOwnPropertyImplementation(JSObject* obj,
633 String* name,
634 LookupResult* result) {
635 obj->LocalLookupRealNamedProperty(name, result);
636
637 if (!result->IsProperty()) {
638 Object* proto = obj->GetPrototype();
639 if (proto->IsJSObject() &&
640 JSObject::cast(proto)->map()->is_hidden_prototype())
641 GetOwnPropertyImplementation(JSObject::cast(proto),
642 name, result);
643 }
644}
645
646
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000647static bool CheckAccessException(LookupResult* result,
648 v8::AccessType access_type) {
649 if (result->type() == CALLBACKS) {
650 Object* callback = result->GetCallbackObject();
651 if (callback->IsAccessorInfo()) {
652 AccessorInfo* info = AccessorInfo::cast(callback);
653 bool can_access =
654 (access_type == v8::ACCESS_HAS &&
655 (info->all_can_read() || info->all_can_write())) ||
656 (access_type == v8::ACCESS_GET && info->all_can_read()) ||
657 (access_type == v8::ACCESS_SET && info->all_can_write());
658 return can_access;
659 }
660 }
661
662 return false;
663}
664
665
666static bool CheckAccess(JSObject* obj,
667 String* name,
668 LookupResult* result,
669 v8::AccessType access_type) {
670 ASSERT(result->IsProperty());
671
672 JSObject* holder = result->holder();
673 JSObject* current = obj;
674 while (true) {
675 if (current->IsAccessCheckNeeded() &&
676 !Top::MayNamedAccess(current, name, access_type)) {
677 // Access check callback denied the access, but some properties
678 // can have a special permissions which override callbacks descision
679 // (currently see v8::AccessControl).
680 break;
681 }
682
683 if (current == holder) {
684 return true;
685 }
686
687 current = JSObject::cast(current->GetPrototype());
688 }
689
690 // API callbacks can have per callback access exceptions.
691 switch (result->type()) {
692 case CALLBACKS: {
693 if (CheckAccessException(result, access_type)) {
694 return true;
695 }
696 break;
697 }
698 case INTERCEPTOR: {
699 // If the object has an interceptor, try real named properties.
700 // Overwrite the result to fetch the correct property later.
701 holder->LookupRealNamedProperty(name, result);
702 if (result->IsProperty()) {
703 if (CheckAccessException(result, access_type)) {
704 return true;
705 }
706 }
707 break;
708 }
709 default:
710 break;
711 }
712
713 Top::ReportFailedAccessCheck(current, access_type);
714 return false;
715}
716
717
718// TODO(1095): we should traverse hidden prototype hierachy as well.
719static bool CheckElementAccess(JSObject* obj,
720 uint32_t index,
721 v8::AccessType access_type) {
722 if (obj->IsAccessCheckNeeded() &&
723 !Top::MayIndexedAccess(obj, index, access_type)) {
724 return false;
725 }
726
727 return true;
728}
729
730
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000731// Enumerator used as indices into the array returned from GetOwnProperty
732enum PropertyDescriptorIndices {
733 IS_ACCESSOR_INDEX,
734 VALUE_INDEX,
735 GETTER_INDEX,
736 SETTER_INDEX,
737 WRITABLE_INDEX,
738 ENUMERABLE_INDEX,
739 CONFIGURABLE_INDEX,
740 DESCRIPTOR_SIZE
741};
742
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000743// Returns an array with the property description:
744// if args[1] is not a property on args[0]
745// returns undefined
746// if args[1] is a data property on args[0]
747// [false, value, Writeable, Enumerable, Configurable]
748// if args[1] is an accessor on args[0]
749// [true, GetFunction, SetFunction, Enumerable, Configurable]
lrn@chromium.org303ada72010-10-27 09:33:13 +0000750static MaybeObject* Runtime_GetOwnProperty(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000751 ASSERT(args.length() == 2);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000752 HandleScope scope;
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000753 Handle<FixedArray> elms = Factory::NewFixedArray(DESCRIPTOR_SIZE);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000754 Handle<JSArray> desc = Factory::NewJSArrayWithElements(elms);
755 LookupResult result;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000756 CONVERT_ARG_CHECKED(JSObject, obj, 0);
757 CONVERT_ARG_CHECKED(String, name, 1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000758
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000759 // This could be an element.
760 uint32_t index;
761 if (name->AsArrayIndex(&index)) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000762 switch (obj->HasLocalElement(index)) {
763 case JSObject::UNDEFINED_ELEMENT:
764 return Heap::undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000765
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000766 case JSObject::STRING_CHARACTER_ELEMENT: {
767 // Special handling of string objects according to ECMAScript 5
768 // 15.5.5.2. Note that this might be a string object with elements
769 // other than the actual string value. This is covered by the
770 // subsequent cases.
771 Handle<JSValue> js_value = Handle<JSValue>::cast(obj);
772 Handle<String> str(String::cast(js_value->value()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000773 Handle<String> substr = SubString(str, index, index + 1, NOT_TENURED);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000774
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000775 elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
776 elms->set(VALUE_INDEX, *substr);
777 elms->set(WRITABLE_INDEX, Heap::false_value());
778 elms->set(ENUMERABLE_INDEX, Heap::false_value());
779 elms->set(CONFIGURABLE_INDEX, Heap::false_value());
780 return *desc;
781 }
782
783 case JSObject::INTERCEPTED_ELEMENT:
784 case JSObject::FAST_ELEMENT: {
785 elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000786 elms->set(VALUE_INDEX, *GetElement(obj, index));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000787 elms->set(WRITABLE_INDEX, Heap::true_value());
788 elms->set(ENUMERABLE_INDEX, Heap::true_value());
789 elms->set(CONFIGURABLE_INDEX, Heap::true_value());
790 return *desc;
791 }
792
793 case JSObject::DICTIONARY_ELEMENT: {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000794 Handle<JSObject> holder = obj;
795 if (obj->IsJSGlobalProxy()) {
796 Object* proto = obj->GetPrototype();
797 if (proto->IsNull()) return Heap::undefined_value();
798 ASSERT(proto->IsJSGlobalObject());
799 holder = Handle<JSObject>(JSObject::cast(proto));
800 }
801 NumberDictionary* dictionary = holder->element_dictionary();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000802 int entry = dictionary->FindEntry(index);
803 ASSERT(entry != NumberDictionary::kNotFound);
804 PropertyDetails details = dictionary->DetailsAt(entry);
805 switch (details.type()) {
806 case CALLBACKS: {
807 // This is an accessor property with getter and/or setter.
808 FixedArray* callbacks =
809 FixedArray::cast(dictionary->ValueAt(entry));
810 elms->set(IS_ACCESSOR_INDEX, Heap::true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000811 if (CheckElementAccess(*obj, index, v8::ACCESS_GET)) {
812 elms->set(GETTER_INDEX, callbacks->get(0));
813 }
814 if (CheckElementAccess(*obj, index, v8::ACCESS_SET)) {
815 elms->set(SETTER_INDEX, callbacks->get(1));
816 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000817 break;
818 }
819 case NORMAL:
820 // This is a data property.
821 elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000822 elms->set(VALUE_INDEX, *GetElement(obj, index));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000823 elms->set(WRITABLE_INDEX, Heap::ToBoolean(!details.IsReadOnly()));
824 break;
825 default:
826 UNREACHABLE();
827 break;
828 }
829 elms->set(ENUMERABLE_INDEX, Heap::ToBoolean(!details.IsDontEnum()));
830 elms->set(CONFIGURABLE_INDEX, Heap::ToBoolean(!details.IsDontDelete()));
831 return *desc;
832 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000833 }
834 }
835
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000836 // Use recursive implementation to also traverse hidden prototypes
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000837 GetOwnPropertyImplementation(*obj, *name, &result);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000838
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000839 if (!result.IsProperty()) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000840 return Heap::undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000841 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000842
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000843 if (!CheckAccess(*obj, *name, &result, v8::ACCESS_HAS)) {
844 return Heap::false_value();
845 }
846
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000847 elms->set(ENUMERABLE_INDEX, Heap::ToBoolean(!result.IsDontEnum()));
848 elms->set(CONFIGURABLE_INDEX, Heap::ToBoolean(!result.IsDontDelete()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000849
850 bool is_js_accessor = (result.type() == CALLBACKS) &&
851 (result.GetCallbackObject()->IsFixedArray());
852
853 if (is_js_accessor) {
854 // __defineGetter__/__defineSetter__ callback.
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000855 elms->set(IS_ACCESSOR_INDEX, Heap::true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000856
857 FixedArray* structure = FixedArray::cast(result.GetCallbackObject());
858 if (CheckAccess(*obj, *name, &result, v8::ACCESS_GET)) {
859 elms->set(GETTER_INDEX, structure->get(0));
860 }
861 if (CheckAccess(*obj, *name, &result, v8::ACCESS_SET)) {
862 elms->set(SETTER_INDEX, structure->get(1));
863 }
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000864 } else {
865 elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
866 elms->set(WRITABLE_INDEX, Heap::ToBoolean(!result.IsReadOnly()));
867
868 PropertyAttributes attrs;
869 Object* value;
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000870 // GetProperty will check access and report any violations.
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000871 { MaybeObject* maybe_value = obj->GetProperty(*obj, &result, *name, &attrs);
872 if (!maybe_value->ToObject(&value)) return maybe_value;
873 }
874 elms->set(VALUE_INDEX, value);
875 }
876
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000877 return *desc;
878}
879
880
lrn@chromium.org303ada72010-10-27 09:33:13 +0000881static MaybeObject* Runtime_PreventExtensions(Arguments args) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000882 ASSERT(args.length() == 1);
883 CONVERT_CHECKED(JSObject, obj, args[0]);
884 return obj->PreventExtensions();
885}
886
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000887
lrn@chromium.org303ada72010-10-27 09:33:13 +0000888static MaybeObject* Runtime_IsExtensible(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000889 ASSERT(args.length() == 1);
890 CONVERT_CHECKED(JSObject, obj, args[0]);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000891 if (obj->IsJSGlobalProxy()) {
892 Object* proto = obj->GetPrototype();
893 if (proto->IsNull()) return Heap::false_value();
894 ASSERT(proto->IsJSGlobalObject());
895 obj = JSObject::cast(proto);
896 }
897 return obj->map()->is_extensible() ? Heap::true_value()
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000898 : Heap::false_value();
899}
900
901
lrn@chromium.org303ada72010-10-27 09:33:13 +0000902static MaybeObject* Runtime_RegExpCompile(Arguments args) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000903 HandleScope scope;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000904 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000905 CONVERT_ARG_CHECKED(JSRegExp, re, 0);
906 CONVERT_ARG_CHECKED(String, pattern, 1);
907 CONVERT_ARG_CHECKED(String, flags, 2);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000908 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags);
909 if (result.is_null()) return Failure::Exception();
910 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000911}
912
913
lrn@chromium.org303ada72010-10-27 09:33:13 +0000914static MaybeObject* Runtime_CreateApiFunction(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000915 HandleScope scope;
916 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000917 CONVERT_ARG_CHECKED(FunctionTemplateInfo, data, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000918 return *Factory::CreateApiFunction(data);
919}
920
921
lrn@chromium.org303ada72010-10-27 09:33:13 +0000922static MaybeObject* Runtime_IsTemplate(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000923 ASSERT(args.length() == 1);
924 Object* arg = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000925 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000926 return Heap::ToBoolean(result);
927}
928
929
lrn@chromium.org303ada72010-10-27 09:33:13 +0000930static MaybeObject* Runtime_GetTemplateField(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000931 ASSERT(args.length() == 2);
932 CONVERT_CHECKED(HeapObject, templ, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000933 CONVERT_CHECKED(Smi, field, args[1]);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000934 int index = field->value();
935 int offset = index * kPointerSize + HeapObject::kHeaderSize;
936 InstanceType type = templ->map()->instance_type();
937 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
938 type == OBJECT_TEMPLATE_INFO_TYPE);
939 RUNTIME_ASSERT(offset > 0);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000940 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000941 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
942 } else {
943 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
944 }
945 return *HeapObject::RawField(templ, offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000946}
947
948
lrn@chromium.org303ada72010-10-27 09:33:13 +0000949static MaybeObject* Runtime_DisableAccessChecks(Arguments args) {
ager@chromium.org870a0b62008-11-04 11:43:05 +0000950 ASSERT(args.length() == 1);
951 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +0000952 Map* old_map = object->map();
953 bool needs_access_checks = old_map->is_access_check_needed();
954 if (needs_access_checks) {
955 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000956 Object* new_map;
957 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
958 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
959 }
ager@chromium.org32912102009-01-16 10:38:43 +0000960
961 Map::cast(new_map)->set_is_access_check_needed(false);
962 object->set_map(Map::cast(new_map));
963 }
ager@chromium.org870a0b62008-11-04 11:43:05 +0000964 return needs_access_checks ? Heap::true_value() : Heap::false_value();
965}
966
967
lrn@chromium.org303ada72010-10-27 09:33:13 +0000968static MaybeObject* Runtime_EnableAccessChecks(Arguments args) {
ager@chromium.org870a0b62008-11-04 11:43:05 +0000969 ASSERT(args.length() == 1);
970 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +0000971 Map* old_map = object->map();
972 if (!old_map->is_access_check_needed()) {
973 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000974 Object* new_map;
975 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
976 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
977 }
ager@chromium.org32912102009-01-16 10:38:43 +0000978
979 Map::cast(new_map)->set_is_access_check_needed(true);
980 object->set_map(Map::cast(new_map));
981 }
ager@chromium.org870a0b62008-11-04 11:43:05 +0000982 return Heap::undefined_value();
983}
984
985
lrn@chromium.org303ada72010-10-27 09:33:13 +0000986static Failure* ThrowRedeclarationError(const char* type, Handle<String> name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000987 HandleScope scope;
988 Handle<Object> type_handle = Factory::NewStringFromAscii(CStrVector(type));
989 Handle<Object> args[2] = { type_handle, name };
990 Handle<Object> error =
991 Factory::NewTypeError("redeclaration", HandleVector(args, 2));
992 return Top::Throw(*error);
993}
994
995
lrn@chromium.org303ada72010-10-27 09:33:13 +0000996static MaybeObject* Runtime_DeclareGlobals(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000997 HandleScope scope;
998 Handle<GlobalObject> global = Handle<GlobalObject>(Top::context()->global());
999
ager@chromium.org3811b432009-10-28 14:53:37 +00001000 Handle<Context> context = args.at<Context>(0);
1001 CONVERT_ARG_CHECKED(FixedArray, pairs, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001002 bool is_eval = Smi::cast(args[2])->value() == 1;
1003
1004 // Compute the property attributes. According to ECMA-262, section
1005 // 13, page 71, the property must be read-only and
1006 // non-deletable. However, neither SpiderMonkey nor KJS creates the
1007 // property as read-only, so we don't either.
1008 PropertyAttributes base = is_eval ? NONE : DONT_DELETE;
1009
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001010 // Traverse the name/value pairs and set the properties.
1011 int length = pairs->length();
1012 for (int i = 0; i < length; i += 2) {
1013 HandleScope scope;
1014 Handle<String> name(String::cast(pairs->get(i)));
1015 Handle<Object> value(pairs->get(i + 1));
1016
1017 // We have to declare a global const property. To capture we only
1018 // assign to it when evaluating the assignment for "const x =
1019 // <expr>" the initial value is the hole.
1020 bool is_const_property = value->IsTheHole();
1021
1022 if (value->IsUndefined() || is_const_property) {
1023 // Lookup the property in the global object, and don't set the
1024 // value of the variable if the property is already there.
1025 LookupResult lookup;
1026 global->Lookup(*name, &lookup);
1027 if (lookup.IsProperty()) {
1028 // Determine if the property is local by comparing the holder
1029 // against the global object. The information will be used to
1030 // avoid throwing re-declaration errors when declaring
1031 // variables or constants that exist in the prototype chain.
1032 bool is_local = (*global == lookup.holder());
1033 // Get the property attributes and determine if the property is
1034 // read-only.
1035 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
1036 bool is_read_only = (attributes & READ_ONLY) != 0;
1037 if (lookup.type() == INTERCEPTOR) {
1038 // If the interceptor says the property is there, we
1039 // just return undefined without overwriting the property.
1040 // Otherwise, we continue to setting the property.
1041 if (attributes != ABSENT) {
1042 // Check if the existing property conflicts with regards to const.
1043 if (is_local && (is_read_only || is_const_property)) {
1044 const char* type = (is_read_only) ? "const" : "var";
1045 return ThrowRedeclarationError(type, name);
1046 };
1047 // The property already exists without conflicting: Go to
1048 // the next declaration.
1049 continue;
1050 }
1051 // Fall-through and introduce the absent property by using
1052 // SetProperty.
1053 } else {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001054 // For const properties, we treat a callback with this name
1055 // even in the prototype as a conflicting declaration.
1056 if (is_const_property && (lookup.type() == CALLBACKS)) {
1057 return ThrowRedeclarationError("const", name);
1058 }
1059 // Otherwise, we check for locally conflicting declarations.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001060 if (is_local && (is_read_only || is_const_property)) {
1061 const char* type = (is_read_only) ? "const" : "var";
1062 return ThrowRedeclarationError(type, name);
1063 }
1064 // The property already exists without conflicting: Go to
1065 // the next declaration.
1066 continue;
1067 }
1068 }
1069 } else {
1070 // Copy the function and update its context. Use it as value.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001071 Handle<SharedFunctionInfo> shared =
1072 Handle<SharedFunctionInfo>::cast(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001073 Handle<JSFunction> function =
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001074 Factory::NewFunctionFromSharedFunctionInfo(shared, context, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001075 value = function;
1076 }
1077
1078 LookupResult lookup;
1079 global->LocalLookup(*name, &lookup);
1080
1081 PropertyAttributes attributes = is_const_property
1082 ? static_cast<PropertyAttributes>(base | READ_ONLY)
1083 : base;
1084
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001085 // There's a local property that we need to overwrite because
1086 // we're either declaring a function or there's an interceptor
1087 // that claims the property is absent.
1088 //
1089 // Check for conflicting re-declarations. We cannot have
1090 // conflicting types in case of intercepted properties because
1091 // they are absent.
1092 if (lookup.IsProperty() &&
1093 (lookup.type() != INTERCEPTOR) &&
1094 (lookup.IsReadOnly() || is_const_property)) {
1095 const char* type = (lookup.IsReadOnly()) ? "const" : "var";
1096 return ThrowRedeclarationError(type, name);
1097 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001098
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001099 // Safari does not allow the invocation of callback setters for
1100 // function declarations. To mimic this behavior, we do not allow
1101 // the invocation of setters for function values. This makes a
1102 // difference for global functions with the same names as event
1103 // handlers such as "function onload() {}". Firefox does call the
1104 // onload setter in those case and Safari does not. We follow
1105 // Safari for compatibility.
1106 if (value->IsJSFunction()) {
1107 RETURN_IF_EMPTY_HANDLE(SetLocalPropertyIgnoreAttributes(global,
1108 name,
1109 value,
1110 attributes));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001111 } else {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001112 RETURN_IF_EMPTY_HANDLE(SetProperty(global, name, value, attributes));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001113 }
1114 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001115
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001116 ASSERT(!Top::has_pending_exception());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001117 return Heap::undefined_value();
1118}
1119
1120
lrn@chromium.org303ada72010-10-27 09:33:13 +00001121static MaybeObject* Runtime_DeclareContextSlot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001122 HandleScope scope;
ager@chromium.org7c537e22008-10-16 08:43:32 +00001123 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001124
ager@chromium.org7c537e22008-10-16 08:43:32 +00001125 CONVERT_ARG_CHECKED(Context, context, 0);
1126 Handle<String> name(String::cast(args[1]));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001127 PropertyAttributes mode =
ager@chromium.org7c537e22008-10-16 08:43:32 +00001128 static_cast<PropertyAttributes>(Smi::cast(args[2])->value());
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001129 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001130 Handle<Object> initial_value(args[3]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001131
1132 // Declarations are always done in the function context.
1133 context = Handle<Context>(context->fcontext());
1134
1135 int index;
1136 PropertyAttributes attributes;
1137 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001138 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001139 context->Lookup(name, flags, &index, &attributes);
1140
1141 if (attributes != ABSENT) {
1142 // The name was declared before; check for conflicting
1143 // re-declarations: This is similar to the code in parser.cc in
1144 // the AstBuildingParser::Declare function.
1145 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
1146 // Functions are not read-only.
1147 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
1148 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
1149 return ThrowRedeclarationError(type, name);
1150 }
1151
1152 // Initialize it if necessary.
1153 if (*initial_value != NULL) {
1154 if (index >= 0) {
1155 // The variable or constant context slot should always be in
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001156 // the function context or the arguments object.
1157 if (holder->IsContext()) {
1158 ASSERT(holder.is_identical_to(context));
1159 if (((attributes & READ_ONLY) == 0) ||
1160 context->get(index)->IsTheHole()) {
1161 context->set(index, *initial_value);
1162 }
1163 } else {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001164 // The holder is an arguments object.
1165 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001166 Handle<Object> result = SetElement(arguments, index, initial_value);
1167 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001168 }
1169 } else {
1170 // Slow case: The property is not in the FixedArray part of the context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001171 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001172 RETURN_IF_EMPTY_HANDLE(
1173 SetProperty(context_ext, name, initial_value, mode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001174 }
1175 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001176
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001177 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001178 // The property is not in the function context. It needs to be
1179 // "declared" in the function context's extension context, or in the
1180 // global context.
1181 Handle<JSObject> context_ext;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001182 if (context->has_extension()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001183 // The function context's extension context exists - use it.
1184 context_ext = Handle<JSObject>(context->extension());
1185 } else {
1186 // The function context's extension context does not exists - allocate
1187 // it.
1188 context_ext = Factory::NewJSObject(Top::context_extension_function());
1189 // And store it in the extension slot.
1190 context->set_extension(*context_ext);
1191 }
1192 ASSERT(*context_ext != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001193
ager@chromium.org7c537e22008-10-16 08:43:32 +00001194 // Declare the property by setting it to the initial value if provided,
1195 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
1196 // constant declarations).
1197 ASSERT(!context_ext->HasLocalProperty(*name));
1198 Handle<Object> value(Heap::undefined_value());
1199 if (*initial_value != NULL) value = initial_value;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001200 // Declaring a const context slot is a conflicting declaration if
1201 // there is a callback with that name in a prototype. It is
1202 // allowed to introduce const variables in
1203 // JSContextExtensionObjects. They are treated specially in
1204 // SetProperty and no setters are invoked for those since they are
1205 // not real JSObjects.
1206 if (initial_value->IsTheHole() &&
1207 !context_ext->IsJSContextExtensionObject()) {
1208 LookupResult lookup;
1209 context_ext->Lookup(*name, &lookup);
1210 if (lookup.IsProperty() && (lookup.type() == CALLBACKS)) {
1211 return ThrowRedeclarationError("const", name);
1212 }
1213 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001214 RETURN_IF_EMPTY_HANDLE(SetProperty(context_ext, name, value, mode));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001215 }
1216
1217 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001218}
1219
1220
lrn@chromium.org303ada72010-10-27 09:33:13 +00001221static MaybeObject* Runtime_InitializeVarGlobal(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001222 NoHandleAllocation nha;
1223
1224 // Determine if we need to assign to the variable if it already
1225 // exists (based on the number of arguments).
1226 RUNTIME_ASSERT(args.length() == 1 || args.length() == 2);
1227 bool assign = args.length() == 2;
1228
1229 CONVERT_ARG_CHECKED(String, name, 0);
1230 GlobalObject* global = Top::context()->global();
1231
1232 // According to ECMA-262, section 12.2, page 62, the property must
1233 // not be deletable.
1234 PropertyAttributes attributes = DONT_DELETE;
1235
1236 // Lookup the property locally in the global object. If it isn't
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001237 // there, there is a property with this name in the prototype chain.
1238 // We follow Safari and Firefox behavior and only set the property
1239 // locally if there is an explicit initialization value that we have
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001240 // to assign to the property.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001241 // Note that objects can have hidden prototypes, so we need to traverse
1242 // the whole chain of hidden prototypes to do a 'local' lookup.
1243 JSObject* real_holder = global;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001244 LookupResult lookup;
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001245 while (true) {
1246 real_holder->LocalLookup(*name, &lookup);
1247 if (lookup.IsProperty()) {
1248 // Determine if this is a redeclaration of something read-only.
1249 if (lookup.IsReadOnly()) {
1250 // If we found readonly property on one of hidden prototypes,
1251 // just shadow it.
1252 if (real_holder != Top::context()->global()) break;
1253 return ThrowRedeclarationError("const", name);
1254 }
1255
1256 // Determine if this is a redeclaration of an intercepted read-only
1257 // property and figure out if the property exists at all.
1258 bool found = true;
1259 PropertyType type = lookup.type();
1260 if (type == INTERCEPTOR) {
1261 HandleScope handle_scope;
1262 Handle<JSObject> holder(real_holder);
1263 PropertyAttributes intercepted = holder->GetPropertyAttribute(*name);
1264 real_holder = *holder;
1265 if (intercepted == ABSENT) {
1266 // The interceptor claims the property isn't there. We need to
1267 // make sure to introduce it.
1268 found = false;
1269 } else if ((intercepted & READ_ONLY) != 0) {
1270 // The property is present, but read-only. Since we're trying to
1271 // overwrite it with a variable declaration we must throw a
1272 // re-declaration error. However if we found readonly property
1273 // on one of hidden prototypes, just shadow it.
1274 if (real_holder != Top::context()->global()) break;
1275 return ThrowRedeclarationError("const", name);
1276 }
1277 }
1278
1279 if (found && !assign) {
1280 // The global property is there and we're not assigning any value
1281 // to it. Just return.
1282 return Heap::undefined_value();
1283 }
1284
1285 // Assign the value (or undefined) to the property.
1286 Object* value = (assign) ? args[1] : Heap::undefined_value();
1287 return real_holder->SetProperty(&lookup, *name, value, attributes);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001288 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001289
1290 Object* proto = real_holder->GetPrototype();
1291 if (!proto->IsJSObject())
1292 break;
1293
1294 if (!JSObject::cast(proto)->map()->is_hidden_prototype())
1295 break;
1296
1297 real_holder = JSObject::cast(proto);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001298 }
1299
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001300 global = Top::context()->global();
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001301 if (assign) return global->SetProperty(*name, args[1], attributes);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001302 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001303}
1304
1305
lrn@chromium.org303ada72010-10-27 09:33:13 +00001306static MaybeObject* Runtime_InitializeConstGlobal(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001307 // All constants are declared with an initial value. The name
1308 // of the constant is the first argument and the initial value
1309 // is the second.
1310 RUNTIME_ASSERT(args.length() == 2);
1311 CONVERT_ARG_CHECKED(String, name, 0);
1312 Handle<Object> value = args.at<Object>(1);
1313
1314 // Get the current global object from top.
1315 GlobalObject* global = Top::context()->global();
1316
1317 // According to ECMA-262, section 12.2, page 62, the property must
1318 // not be deletable. Since it's a const, it must be READ_ONLY too.
1319 PropertyAttributes attributes =
1320 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
1321
1322 // Lookup the property locally in the global object. If it isn't
1323 // there, we add the property and take special precautions to always
1324 // add it as a local property even in case of callbacks in the
1325 // prototype chain (this rules out using SetProperty).
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001326 // We use SetLocalPropertyIgnoreAttributes instead
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001327 LookupResult lookup;
1328 global->LocalLookup(*name, &lookup);
1329 if (!lookup.IsProperty()) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001330 return global->SetLocalPropertyIgnoreAttributes(*name,
1331 *value,
1332 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001333 }
1334
1335 // Determine if this is a redeclaration of something not
1336 // read-only. In case the result is hidden behind an interceptor we
1337 // need to ask it for the property attributes.
1338 if (!lookup.IsReadOnly()) {
1339 if (lookup.type() != INTERCEPTOR) {
1340 return ThrowRedeclarationError("var", name);
1341 }
1342
1343 PropertyAttributes intercepted = global->GetPropertyAttribute(*name);
1344
1345 // Throw re-declaration error if the intercepted property is present
1346 // but not read-only.
1347 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
1348 return ThrowRedeclarationError("var", name);
1349 }
1350
1351 // Restore global object from context (in case of GC) and continue
1352 // with setting the value because the property is either absent or
1353 // read-only. We also have to do redo the lookup.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001354 HandleScope handle_scope;
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001355 Handle<GlobalObject> global(Top::context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001356
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001357 // BUG 1213575: Handle the case where we have to set a read-only
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001358 // property through an interceptor and only do it if it's
1359 // uninitialized, e.g. the hole. Nirk...
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001360 RETURN_IF_EMPTY_HANDLE(SetProperty(global, name, value, attributes));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001361 return *value;
1362 }
1363
1364 // Set the value, but only we're assigning the initial value to a
1365 // constant. For now, we determine this by checking if the
1366 // current value is the hole.
1367 PropertyType type = lookup.type();
1368 if (type == FIELD) {
1369 FixedArray* properties = global->properties();
1370 int index = lookup.GetFieldIndex();
1371 if (properties->get(index)->IsTheHole()) {
1372 properties->set(index, *value);
1373 }
1374 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001375 if (global->GetNormalizedProperty(&lookup)->IsTheHole()) {
1376 global->SetNormalizedProperty(&lookup, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001377 }
1378 } else {
1379 // Ignore re-initialization of constants that have already been
1380 // assigned a function value.
1381 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
1382 }
1383
1384 // Use the set value as the result of the operation.
1385 return *value;
1386}
1387
1388
lrn@chromium.org303ada72010-10-27 09:33:13 +00001389static MaybeObject* Runtime_InitializeConstContextSlot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001390 HandleScope scope;
1391 ASSERT(args.length() == 3);
1392
1393 Handle<Object> value(args[0]);
1394 ASSERT(!value->IsTheHole());
1395 CONVERT_ARG_CHECKED(Context, context, 1);
1396 Handle<String> name(String::cast(args[2]));
1397
1398 // Initializations are always done in the function context.
1399 context = Handle<Context>(context->fcontext());
1400
1401 int index;
1402 PropertyAttributes attributes;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001403 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001404 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001405 context->Lookup(name, flags, &index, &attributes);
1406
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001407 // In most situations, the property introduced by the const
1408 // declaration should be present in the context extension object.
1409 // However, because declaration and initialization are separate, the
1410 // property might have been deleted (if it was introduced by eval)
1411 // before we reach the initialization point.
1412 //
1413 // Example:
1414 //
1415 // function f() { eval("delete x; const x;"); }
1416 //
1417 // In that case, the initialization behaves like a normal assignment
1418 // to property 'x'.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001419 if (index >= 0) {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001420 // Property was found in a context.
1421 if (holder->IsContext()) {
1422 // The holder cannot be the function context. If it is, there
1423 // should have been a const redeclaration error when declaring
1424 // the const property.
1425 ASSERT(!holder.is_identical_to(context));
1426 if ((attributes & READ_ONLY) == 0) {
1427 Handle<Context>::cast(holder)->set(index, *value);
1428 }
1429 } else {
1430 // The holder is an arguments object.
1431 ASSERT((attributes & READ_ONLY) == 0);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001432 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
1433 SetElement(arguments, index, value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001434 }
1435 return *value;
1436 }
1437
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001438 // The property could not be found, we introduce it in the global
1439 // context.
1440 if (attributes == ABSENT) {
1441 Handle<JSObject> global = Handle<JSObject>(Top::context()->global());
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001442 RETURN_IF_EMPTY_HANDLE(SetProperty(global, name, value, NONE));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001443 return *value;
1444 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001445
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001446 // The property was present in a context extension object.
1447 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001448
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001449 if (*context_ext == context->extension()) {
1450 // This is the property that was introduced by the const
1451 // declaration. Set it if it hasn't been set before. NOTE: We
1452 // cannot use GetProperty() to get the current value as it
1453 // 'unholes' the value.
1454 LookupResult lookup;
1455 context_ext->LocalLookupRealNamedProperty(*name, &lookup);
1456 ASSERT(lookup.IsProperty()); // the property was declared
1457 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
1458
1459 PropertyType type = lookup.type();
1460 if (type == FIELD) {
1461 FixedArray* properties = context_ext->properties();
1462 int index = lookup.GetFieldIndex();
1463 if (properties->get(index)->IsTheHole()) {
1464 properties->set(index, *value);
1465 }
1466 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001467 if (context_ext->GetNormalizedProperty(&lookup)->IsTheHole()) {
1468 context_ext->SetNormalizedProperty(&lookup, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001469 }
1470 } else {
1471 // We should not reach here. Any real, named property should be
1472 // either a field or a dictionary slot.
1473 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001474 }
1475 } else {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001476 // The property was found in a different context extension object.
1477 // Set it if it is not a read-only property.
1478 if ((attributes & READ_ONLY) == 0) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001479 RETURN_IF_EMPTY_HANDLE(
1480 SetProperty(context_ext, name, value, attributes));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001481 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001482 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001483
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001484 return *value;
1485}
1486
1487
lrn@chromium.org303ada72010-10-27 09:33:13 +00001488static MaybeObject* Runtime_OptimizeObjectForAddingMultipleProperties(
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001489 Arguments args) {
1490 HandleScope scope;
1491 ASSERT(args.length() == 2);
1492 CONVERT_ARG_CHECKED(JSObject, object, 0);
1493 CONVERT_SMI_CHECKED(properties, args[1]);
1494 if (object->HasFastProperties()) {
1495 NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
1496 }
1497 return *object;
1498}
1499
1500
lrn@chromium.org303ada72010-10-27 09:33:13 +00001501static MaybeObject* Runtime_RegExpExec(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001502 HandleScope scope;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001503 ASSERT(args.length() == 4);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001504 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
1505 CONVERT_ARG_CHECKED(String, subject, 1);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001506 // Due to the way the JS calls are constructed this must be less than the
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001507 // length of a string, i.e. it is always a Smi. We check anyway for security.
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001508 CONVERT_SMI_CHECKED(index, args[2]);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001509 CONVERT_ARG_CHECKED(JSArray, last_match_info, 3);
ager@chromium.org41826e72009-03-30 13:30:57 +00001510 RUNTIME_ASSERT(last_match_info->HasFastElements());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001511 RUNTIME_ASSERT(index >= 0);
1512 RUNTIME_ASSERT(index <= subject->length());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001513 Counters::regexp_entry_runtime.Increment();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001514 Handle<Object> result = RegExpImpl::Exec(regexp,
1515 subject,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001516 index,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001517 last_match_info);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001518 if (result.is_null()) return Failure::Exception();
1519 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001520}
1521
1522
lrn@chromium.org303ada72010-10-27 09:33:13 +00001523static MaybeObject* Runtime_RegExpConstructResult(Arguments args) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001524 ASSERT(args.length() == 3);
1525 CONVERT_SMI_CHECKED(elements_count, args[0]);
1526 if (elements_count > JSArray::kMaxFastElementsLength) {
1527 return Top::ThrowIllegalOperation();
1528 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00001529 Object* new_object;
1530 { MaybeObject* maybe_new_object =
1531 Heap::AllocateFixedArrayWithHoles(elements_count);
1532 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1533 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001534 FixedArray* elements = FixedArray::cast(new_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001535 { MaybeObject* maybe_new_object = Heap::AllocateRaw(JSRegExpResult::kSize,
1536 NEW_SPACE,
1537 OLD_POINTER_SPACE);
1538 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1539 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001540 {
1541 AssertNoAllocation no_gc;
1542 HandleScope scope;
1543 reinterpret_cast<HeapObject*>(new_object)->
1544 set_map(Top::global_context()->regexp_result_map());
1545 }
1546 JSArray* array = JSArray::cast(new_object);
1547 array->set_properties(Heap::empty_fixed_array());
1548 array->set_elements(elements);
1549 array->set_length(Smi::FromInt(elements_count));
1550 // Write in-object properties after the length of the array.
1551 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]);
1552 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]);
1553 return array;
1554}
1555
1556
lrn@chromium.org303ada72010-10-27 09:33:13 +00001557static MaybeObject* Runtime_RegExpInitializeObject(Arguments args) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00001558 AssertNoAllocation no_alloc;
1559 ASSERT(args.length() == 5);
1560 CONVERT_CHECKED(JSRegExp, regexp, args[0]);
1561 CONVERT_CHECKED(String, source, args[1]);
1562
1563 Object* global = args[2];
1564 if (!global->IsTrue()) global = Heap::false_value();
1565
1566 Object* ignoreCase = args[3];
1567 if (!ignoreCase->IsTrue()) ignoreCase = Heap::false_value();
1568
1569 Object* multiline = args[4];
1570 if (!multiline->IsTrue()) multiline = Heap::false_value();
1571
1572 Map* map = regexp->map();
1573 Object* constructor = map->constructor();
1574 if (constructor->IsJSFunction() &&
1575 JSFunction::cast(constructor)->initial_map() == map) {
1576 // If we still have the original map, set in-object properties directly.
1577 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source);
1578 // TODO(lrn): Consider skipping write barrier on booleans as well.
1579 // Both true and false should be in oldspace at all times.
1580 regexp->InObjectPropertyAtPut(JSRegExp::kGlobalFieldIndex, global);
1581 regexp->InObjectPropertyAtPut(JSRegExp::kIgnoreCaseFieldIndex, ignoreCase);
1582 regexp->InObjectPropertyAtPut(JSRegExp::kMultilineFieldIndex, multiline);
1583 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
1584 Smi::FromInt(0),
1585 SKIP_WRITE_BARRIER);
1586 return regexp;
1587 }
1588
lrn@chromium.org303ada72010-10-27 09:33:13 +00001589 // Map has changed, so use generic, but slower, method. Since these
1590 // properties were all added as DONT_DELETE they must be present and
1591 // normal so no failures can be expected.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001592 PropertyAttributes final =
1593 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
1594 PropertyAttributes writable =
1595 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001596 MaybeObject* result;
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001597 result = regexp->SetLocalPropertyIgnoreAttributes(Heap::source_symbol(),
1598 source,
1599 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001600 ASSERT(!result->IsFailure());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001601 result = regexp->SetLocalPropertyIgnoreAttributes(Heap::global_symbol(),
1602 global,
1603 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001604 ASSERT(!result->IsFailure());
1605 result =
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001606 regexp->SetLocalPropertyIgnoreAttributes(Heap::ignore_case_symbol(),
1607 ignoreCase,
1608 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001609 ASSERT(!result->IsFailure());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001610 result = regexp->SetLocalPropertyIgnoreAttributes(Heap::multiline_symbol(),
1611 multiline,
1612 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001613 ASSERT(!result->IsFailure());
1614 result =
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001615 regexp->SetLocalPropertyIgnoreAttributes(Heap::last_index_symbol(),
1616 Smi::FromInt(0),
1617 writable);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001618 ASSERT(!result->IsFailure());
1619 USE(result);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001620 return regexp;
1621}
1622
1623
lrn@chromium.org303ada72010-10-27 09:33:13 +00001624static MaybeObject* Runtime_FinishArrayPrototypeSetup(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001625 HandleScope scope;
1626 ASSERT(args.length() == 1);
1627 CONVERT_ARG_CHECKED(JSArray, prototype, 0);
1628 // This is necessary to enable fast checks for absence of elements
1629 // on Array.prototype and below.
1630 prototype->set_elements(Heap::empty_fixed_array());
1631 return Smi::FromInt(0);
1632}
1633
1634
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001635static Handle<JSFunction> InstallBuiltin(Handle<JSObject> holder,
1636 const char* name,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001637 Builtins::Name builtin_name) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001638 Handle<String> key = Factory::LookupAsciiSymbol(name);
1639 Handle<Code> code(Builtins::builtin(builtin_name));
1640 Handle<JSFunction> optimized = Factory::NewFunction(key,
1641 JS_OBJECT_TYPE,
1642 JSObject::kHeaderSize,
1643 code,
1644 false);
1645 optimized->shared()->DontAdaptArguments();
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001646 SetProperty(holder, key, optimized, NONE);
1647 return optimized;
1648}
1649
1650
lrn@chromium.org303ada72010-10-27 09:33:13 +00001651static MaybeObject* Runtime_SpecialArrayFunctions(Arguments args) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001652 HandleScope scope;
1653 ASSERT(args.length() == 1);
1654 CONVERT_ARG_CHECKED(JSObject, holder, 0);
1655
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001656 InstallBuiltin(holder, "pop", Builtins::ArrayPop);
1657 InstallBuiltin(holder, "push", Builtins::ArrayPush);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001658 InstallBuiltin(holder, "shift", Builtins::ArrayShift);
1659 InstallBuiltin(holder, "unshift", Builtins::ArrayUnshift);
1660 InstallBuiltin(holder, "slice", Builtins::ArraySlice);
1661 InstallBuiltin(holder, "splice", Builtins::ArraySplice);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001662 InstallBuiltin(holder, "concat", Builtins::ArrayConcat);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001663
1664 return *holder;
1665}
1666
1667
lrn@chromium.org303ada72010-10-27 09:33:13 +00001668static MaybeObject* Runtime_GetGlobalReceiver(Arguments args) {
ager@chromium.org357bf652010-04-12 11:30:10 +00001669 // Returns a real global receiver, not one of builtins object.
1670 Context* global_context = Top::context()->global()->global_context();
1671 return global_context->global()->global_receiver();
1672}
1673
1674
lrn@chromium.org303ada72010-10-27 09:33:13 +00001675static MaybeObject* Runtime_MaterializeRegExpLiteral(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001676 HandleScope scope;
1677 ASSERT(args.length() == 4);
1678 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
1679 int index = Smi::cast(args[1])->value();
1680 Handle<String> pattern = args.at<String>(2);
1681 Handle<String> flags = args.at<String>(3);
1682
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001683 // Get the RegExp function from the context in the literals array.
1684 // This is the RegExp function from the context in which the
1685 // function was created. We do not use the RegExp function from the
1686 // current global context because this might be the RegExp function
1687 // from another context which we should not have access to.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001688 Handle<JSFunction> constructor =
ager@chromium.org236ad962008-09-25 09:45:57 +00001689 Handle<JSFunction>(
1690 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001691 // Compute the regular expression literal.
1692 bool has_pending_exception;
1693 Handle<Object> regexp =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001694 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
1695 &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001696 if (has_pending_exception) {
1697 ASSERT(Top::has_pending_exception());
1698 return Failure::Exception();
1699 }
1700 literals->set(index, *regexp);
1701 return *regexp;
1702}
1703
1704
lrn@chromium.org303ada72010-10-27 09:33:13 +00001705static MaybeObject* Runtime_FunctionGetName(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001706 NoHandleAllocation ha;
1707 ASSERT(args.length() == 1);
1708
1709 CONVERT_CHECKED(JSFunction, f, args[0]);
1710 return f->shared()->name();
1711}
1712
1713
lrn@chromium.org303ada72010-10-27 09:33:13 +00001714static MaybeObject* Runtime_FunctionSetName(Arguments args) {
ager@chromium.org236ad962008-09-25 09:45:57 +00001715 NoHandleAllocation ha;
1716 ASSERT(args.length() == 2);
1717
1718 CONVERT_CHECKED(JSFunction, f, args[0]);
1719 CONVERT_CHECKED(String, name, args[1]);
1720 f->shared()->set_name(name);
1721 return Heap::undefined_value();
1722}
1723
1724
lrn@chromium.org303ada72010-10-27 09:33:13 +00001725static MaybeObject* Runtime_FunctionRemovePrototype(Arguments args) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001726 NoHandleAllocation ha;
1727 ASSERT(args.length() == 1);
1728
1729 CONVERT_CHECKED(JSFunction, f, args[0]);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001730 Object* obj;
1731 { MaybeObject* maybe_obj = f->RemovePrototype();
1732 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1733 }
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001734
1735 return Heap::undefined_value();
1736}
1737
1738
lrn@chromium.org303ada72010-10-27 09:33:13 +00001739static MaybeObject* Runtime_FunctionGetScript(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001740 HandleScope scope;
1741 ASSERT(args.length() == 1);
1742
1743 CONVERT_CHECKED(JSFunction, fun, args[0]);
1744 Handle<Object> script = Handle<Object>(fun->shared()->script());
1745 if (!script->IsScript()) return Heap::undefined_value();
1746
1747 return *GetScriptWrapper(Handle<Script>::cast(script));
1748}
1749
1750
lrn@chromium.org303ada72010-10-27 09:33:13 +00001751static MaybeObject* Runtime_FunctionGetSourceCode(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001752 NoHandleAllocation ha;
1753 ASSERT(args.length() == 1);
1754
1755 CONVERT_CHECKED(JSFunction, f, args[0]);
1756 return f->shared()->GetSourceCode();
1757}
1758
1759
lrn@chromium.org303ada72010-10-27 09:33:13 +00001760static MaybeObject* Runtime_FunctionGetScriptSourcePosition(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001761 NoHandleAllocation ha;
1762 ASSERT(args.length() == 1);
1763
1764 CONVERT_CHECKED(JSFunction, fun, args[0]);
1765 int pos = fun->shared()->start_position();
1766 return Smi::FromInt(pos);
1767}
1768
1769
lrn@chromium.org303ada72010-10-27 09:33:13 +00001770static MaybeObject* Runtime_FunctionGetPositionForOffset(Arguments args) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001771 ASSERT(args.length() == 2);
1772
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001773 CONVERT_CHECKED(Code, code, args[0]);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001774 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
1775
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001776 RUNTIME_ASSERT(0 <= offset && offset < code->Size());
1777
1778 Address pc = code->address() + offset;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001779 return Smi::FromInt(code->SourcePosition(pc));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001780}
1781
1782
1783
lrn@chromium.org303ada72010-10-27 09:33:13 +00001784static MaybeObject* Runtime_FunctionSetInstanceClassName(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001785 NoHandleAllocation ha;
1786 ASSERT(args.length() == 2);
1787
1788 CONVERT_CHECKED(JSFunction, fun, args[0]);
1789 CONVERT_CHECKED(String, name, args[1]);
1790 fun->SetInstanceClassName(name);
1791 return Heap::undefined_value();
1792}
1793
1794
lrn@chromium.org303ada72010-10-27 09:33:13 +00001795static MaybeObject* Runtime_FunctionSetLength(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001796 NoHandleAllocation ha;
1797 ASSERT(args.length() == 2);
1798
1799 CONVERT_CHECKED(JSFunction, fun, args[0]);
1800 CONVERT_CHECKED(Smi, length, args[1]);
1801 fun->shared()->set_length(length->value());
1802 return length;
1803}
1804
1805
lrn@chromium.org303ada72010-10-27 09:33:13 +00001806static MaybeObject* Runtime_FunctionSetPrototype(Arguments args) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001807 NoHandleAllocation ha;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001808 ASSERT(args.length() == 2);
1809
1810 CONVERT_CHECKED(JSFunction, fun, args[0]);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001811 ASSERT(fun->should_have_prototype());
lrn@chromium.org303ada72010-10-27 09:33:13 +00001812 Object* obj;
1813 { MaybeObject* maybe_obj =
1814 Accessors::FunctionSetPrototype(fun, args[1], NULL);
1815 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1816 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001817 return args[0]; // return TOS
1818}
1819
1820
lrn@chromium.org303ada72010-10-27 09:33:13 +00001821static MaybeObject* Runtime_FunctionIsAPIFunction(Arguments args) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001822 NoHandleAllocation ha;
1823 ASSERT(args.length() == 1);
1824
1825 CONVERT_CHECKED(JSFunction, f, args[0]);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001826 return f->shared()->IsApiFunction() ? Heap::true_value()
1827 : Heap::false_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001828}
1829
lrn@chromium.org303ada72010-10-27 09:33:13 +00001830static MaybeObject* Runtime_FunctionIsBuiltin(Arguments args) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001831 NoHandleAllocation ha;
1832 ASSERT(args.length() == 1);
1833
1834 CONVERT_CHECKED(JSFunction, f, args[0]);
1835 return f->IsBuiltin() ? Heap::true_value() : Heap::false_value();
1836}
1837
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001838
lrn@chromium.org303ada72010-10-27 09:33:13 +00001839static MaybeObject* Runtime_SetCode(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001840 HandleScope scope;
1841 ASSERT(args.length() == 2);
1842
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001843 CONVERT_ARG_CHECKED(JSFunction, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001844 Handle<Object> code = args.at<Object>(1);
1845
1846 Handle<Context> context(target->context());
1847
1848 if (!code->IsNull()) {
1849 RUNTIME_ASSERT(code->IsJSFunction());
1850 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001851 Handle<SharedFunctionInfo> shared(fun->shared());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001852
1853 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001854 return Failure::Exception();
1855 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001856 // Since we don't store the source for this we should never
1857 // optimize this.
1858 shared->code()->set_optimizable(false);
1859
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001860 // Set the code, scope info, formal parameter count,
1861 // and the length of the target function.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00001862 target->shared()->set_code(shared->code());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001863 target->ReplaceCode(shared->code());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001864 target->shared()->set_scope_info(shared->scope_info());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001865 target->shared()->set_length(shared->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001866 target->shared()->set_formal_parameter_count(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001867 shared->formal_parameter_count());
ager@chromium.org7c537e22008-10-16 08:43:32 +00001868 // Set the source code of the target function to undefined.
1869 // SetCode is only used for built-in constructors like String,
1870 // Array, and Object, and some web code
1871 // doesn't like seeing source code for constructors.
1872 target->shared()->set_script(Heap::undefined_value());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001873 target->shared()->code()->set_optimizable(false);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001874 // Clear the optimization hints related to the compiled code as these are no
1875 // longer valid when the code is overwritten.
1876 target->shared()->ClearThisPropertyAssignmentsInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001877 context = Handle<Context>(fun->context());
1878
1879 // Make sure we get a fresh copy of the literal vector to avoid
1880 // cross context contamination.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001881 int number_of_literals = fun->NumberOfLiterals();
1882 Handle<FixedArray> literals =
1883 Factory::NewFixedArray(number_of_literals, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001884 if (number_of_literals > 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001885 // Insert the object, regexp and array functions in the literals
1886 // array prefix. These are the functions that will be used when
1887 // creating object, regexp and array literals.
ager@chromium.org236ad962008-09-25 09:45:57 +00001888 literals->set(JSFunction::kLiteralGlobalContextIndex,
1889 context->global_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001890 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001891 // It's okay to skip the write barrier here because the literals
1892 // are guaranteed to be in old space.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001893 target->set_literals(*literals, SKIP_WRITE_BARRIER);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001894 target->set_next_function_link(Heap::undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001895 }
1896
1897 target->set_context(*context);
1898 return *target;
1899}
1900
1901
lrn@chromium.org303ada72010-10-27 09:33:13 +00001902static MaybeObject* Runtime_SetExpectedNumberOfProperties(Arguments args) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001903 HandleScope scope;
1904 ASSERT(args.length() == 2);
1905 CONVERT_ARG_CHECKED(JSFunction, function, 0);
1906 CONVERT_SMI_CHECKED(num, args[1]);
1907 RUNTIME_ASSERT(num >= 0);
1908 SetExpectedNofProperties(function, num);
1909 return Heap::undefined_value();
1910}
1911
1912
lrn@chromium.org303ada72010-10-27 09:33:13 +00001913MUST_USE_RESULT static MaybeObject* CharFromCode(Object* char_code) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001914 uint32_t code;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001915 if (char_code->ToArrayIndex(&code)) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001916 if (code <= 0xffff) {
1917 return Heap::LookupSingleCharacterStringFromCode(code);
1918 }
1919 }
1920 return Heap::empty_string();
1921}
1922
1923
lrn@chromium.org303ada72010-10-27 09:33:13 +00001924static MaybeObject* Runtime_StringCharCodeAt(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001925 NoHandleAllocation ha;
1926 ASSERT(args.length() == 2);
1927
1928 CONVERT_CHECKED(String, subject, args[0]);
1929 Object* index = args[1];
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001930 RUNTIME_ASSERT(index->IsNumber());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001931
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001932 uint32_t i = 0;
1933 if (index->IsSmi()) {
1934 int value = Smi::cast(index)->value();
1935 if (value < 0) return Heap::nan_value();
1936 i = value;
1937 } else {
1938 ASSERT(index->IsHeapNumber());
1939 double value = HeapNumber::cast(index)->value();
1940 i = static_cast<uint32_t>(DoubleToInteger(value));
kasperl@chromium.org74e4e5e2010-01-25 10:15:52 +00001941 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001942
1943 // Flatten the string. If someone wants to get a char at an index
1944 // in a cons string, it is likely that more indices will be
1945 // accessed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001946 Object* flat;
1947 { MaybeObject* maybe_flat = subject->TryFlatten();
1948 if (!maybe_flat->ToObject(&flat)) return maybe_flat;
1949 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001950 subject = String::cast(flat);
1951
1952 if (i >= static_cast<uint32_t>(subject->length())) {
1953 return Heap::nan_value();
1954 }
1955
1956 return Smi::FromInt(subject->Get(i));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001957}
1958
1959
lrn@chromium.org303ada72010-10-27 09:33:13 +00001960static MaybeObject* Runtime_CharFromCode(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001961 NoHandleAllocation ha;
1962 ASSERT(args.length() == 1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001963 return CharFromCode(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001964}
1965
lrn@chromium.org25156de2010-04-06 13:10:27 +00001966
1967class FixedArrayBuilder {
1968 public:
1969 explicit FixedArrayBuilder(int initial_capacity)
1970 : array_(Factory::NewFixedArrayWithHoles(initial_capacity)),
1971 length_(0) {
1972 // Require a non-zero initial size. Ensures that doubling the size to
1973 // extend the array will work.
1974 ASSERT(initial_capacity > 0);
1975 }
1976
1977 explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
1978 : array_(backing_store),
1979 length_(0) {
1980 // Require a non-zero initial size. Ensures that doubling the size to
1981 // extend the array will work.
1982 ASSERT(backing_store->length() > 0);
1983 }
1984
1985 bool HasCapacity(int elements) {
1986 int length = array_->length();
1987 int required_length = length_ + elements;
1988 return (length >= required_length);
1989 }
1990
1991 void EnsureCapacity(int elements) {
1992 int length = array_->length();
1993 int required_length = length_ + elements;
1994 if (length < required_length) {
1995 int new_length = length;
1996 do {
1997 new_length *= 2;
1998 } while (new_length < required_length);
1999 Handle<FixedArray> extended_array =
2000 Factory::NewFixedArrayWithHoles(new_length);
2001 array_->CopyTo(0, *extended_array, 0, length_);
2002 array_ = extended_array;
2003 }
2004 }
2005
2006 void Add(Object* value) {
2007 ASSERT(length_ < capacity());
2008 array_->set(length_, value);
2009 length_++;
2010 }
2011
2012 void Add(Smi* value) {
2013 ASSERT(length_ < capacity());
2014 array_->set(length_, value);
2015 length_++;
2016 }
2017
2018 Handle<FixedArray> array() {
2019 return array_;
2020 }
2021
2022 int length() {
2023 return length_;
2024 }
2025
2026 int capacity() {
2027 return array_->length();
2028 }
2029
2030 Handle<JSArray> ToJSArray() {
2031 Handle<JSArray> result_array = Factory::NewJSArrayWithElements(array_);
2032 result_array->set_length(Smi::FromInt(length_));
2033 return result_array;
2034 }
2035
2036 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
2037 target_array->set_elements(*array_);
2038 target_array->set_length(Smi::FromInt(length_));
2039 return target_array;
2040 }
2041
2042 private:
2043 Handle<FixedArray> array_;
2044 int length_;
2045};
2046
2047
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002048// Forward declarations.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002049const int kStringBuilderConcatHelperLengthBits = 11;
2050const int kStringBuilderConcatHelperPositionBits = 19;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002051
2052template <typename schar>
2053static inline void StringBuilderConcatHelper(String*,
2054 schar*,
2055 FixedArray*,
2056 int);
2057
lrn@chromium.org25156de2010-04-06 13:10:27 +00002058typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
2059 StringBuilderSubstringLength;
2060typedef BitField<int,
2061 kStringBuilderConcatHelperLengthBits,
2062 kStringBuilderConcatHelperPositionBits>
2063 StringBuilderSubstringPosition;
2064
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002065
2066class ReplacementStringBuilder {
2067 public:
2068 ReplacementStringBuilder(Handle<String> subject, int estimated_part_count)
lrn@chromium.org25156de2010-04-06 13:10:27 +00002069 : array_builder_(estimated_part_count),
2070 subject_(subject),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002071 character_count_(0),
ager@chromium.org5ec48922009-05-05 07:25:34 +00002072 is_ascii_(subject->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002073 // Require a non-zero initial size. Ensures that doubling the size to
2074 // extend the array will work.
2075 ASSERT(estimated_part_count > 0);
2076 }
2077
lrn@chromium.org25156de2010-04-06 13:10:27 +00002078 static inline void AddSubjectSlice(FixedArrayBuilder* builder,
2079 int from,
2080 int to) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002081 ASSERT(from >= 0);
2082 int length = to - from;
2083 ASSERT(length > 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002084 if (StringBuilderSubstringLength::is_valid(length) &&
2085 StringBuilderSubstringPosition::is_valid(from)) {
2086 int encoded_slice = StringBuilderSubstringLength::encode(length) |
2087 StringBuilderSubstringPosition::encode(from);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002088 builder->Add(Smi::FromInt(encoded_slice));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002089 } else {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002090 // Otherwise encode as two smis.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002091 builder->Add(Smi::FromInt(-length));
2092 builder->Add(Smi::FromInt(from));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002093 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00002094 }
2095
2096
2097 void EnsureCapacity(int elements) {
2098 array_builder_.EnsureCapacity(elements);
2099 }
2100
2101
2102 void AddSubjectSlice(int from, int to) {
2103 AddSubjectSlice(&array_builder_, from, to);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002104 IncrementCharacterCount(to - from);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002105 }
2106
2107
2108 void AddString(Handle<String> string) {
2109 int length = string->length();
2110 ASSERT(length > 0);
2111 AddElement(*string);
ager@chromium.org5ec48922009-05-05 07:25:34 +00002112 if (!string->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002113 is_ascii_ = false;
2114 }
2115 IncrementCharacterCount(length);
2116 }
2117
2118
2119 Handle<String> ToString() {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002120 if (array_builder_.length() == 0) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002121 return Factory::empty_string();
2122 }
2123
2124 Handle<String> joined_string;
2125 if (is_ascii_) {
2126 joined_string = NewRawAsciiString(character_count_);
2127 AssertNoAllocation no_alloc;
2128 SeqAsciiString* seq = SeqAsciiString::cast(*joined_string);
2129 char* char_buffer = seq->GetChars();
2130 StringBuilderConcatHelper(*subject_,
2131 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002132 *array_builder_.array(),
2133 array_builder_.length());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002134 } else {
2135 // Non-ASCII.
2136 joined_string = NewRawTwoByteString(character_count_);
2137 AssertNoAllocation no_alloc;
2138 SeqTwoByteString* seq = SeqTwoByteString::cast(*joined_string);
2139 uc16* char_buffer = seq->GetChars();
2140 StringBuilderConcatHelper(*subject_,
2141 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002142 *array_builder_.array(),
2143 array_builder_.length());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002144 }
2145 return joined_string;
2146 }
2147
2148
2149 void IncrementCharacterCount(int by) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002150 if (character_count_ > String::kMaxLength - by) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002151 V8::FatalProcessOutOfMemory("String.replace result too large.");
2152 }
2153 character_count_ += by;
2154 }
2155
lrn@chromium.org25156de2010-04-06 13:10:27 +00002156 Handle<JSArray> GetParts() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002157 return array_builder_.ToJSArray();
lrn@chromium.org25156de2010-04-06 13:10:27 +00002158 }
kmillikin@chromium.orgd9825192010-03-30 08:36:16 +00002159
lrn@chromium.org25156de2010-04-06 13:10:27 +00002160 private:
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002161 Handle<String> NewRawAsciiString(int size) {
2162 CALL_HEAP_FUNCTION(Heap::AllocateRawAsciiString(size), String);
2163 }
2164
2165
2166 Handle<String> NewRawTwoByteString(int size) {
2167 CALL_HEAP_FUNCTION(Heap::AllocateRawTwoByteString(size), String);
2168 }
2169
2170
2171 void AddElement(Object* element) {
2172 ASSERT(element->IsSmi() || element->IsString());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002173 ASSERT(array_builder_.capacity() > array_builder_.length());
2174 array_builder_.Add(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002175 }
2176
lrn@chromium.org25156de2010-04-06 13:10:27 +00002177 FixedArrayBuilder array_builder_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002178 Handle<String> subject_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002179 int character_count_;
2180 bool is_ascii_;
2181};
2182
2183
2184class CompiledReplacement {
2185 public:
2186 CompiledReplacement()
2187 : parts_(1), replacement_substrings_(0) {}
2188
2189 void Compile(Handle<String> replacement,
2190 int capture_count,
2191 int subject_length);
2192
2193 void Apply(ReplacementStringBuilder* builder,
2194 int match_from,
2195 int match_to,
2196 Handle<JSArray> last_match_info);
2197
2198 // Number of distinct parts of the replacement pattern.
2199 int parts() {
2200 return parts_.length();
2201 }
2202 private:
2203 enum PartType {
2204 SUBJECT_PREFIX = 1,
2205 SUBJECT_SUFFIX,
2206 SUBJECT_CAPTURE,
2207 REPLACEMENT_SUBSTRING,
2208 REPLACEMENT_STRING,
2209
2210 NUMBER_OF_PART_TYPES
2211 };
2212
2213 struct ReplacementPart {
2214 static inline ReplacementPart SubjectMatch() {
2215 return ReplacementPart(SUBJECT_CAPTURE, 0);
2216 }
2217 static inline ReplacementPart SubjectCapture(int capture_index) {
2218 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
2219 }
2220 static inline ReplacementPart SubjectPrefix() {
2221 return ReplacementPart(SUBJECT_PREFIX, 0);
2222 }
2223 static inline ReplacementPart SubjectSuffix(int subject_length) {
2224 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
2225 }
2226 static inline ReplacementPart ReplacementString() {
2227 return ReplacementPart(REPLACEMENT_STRING, 0);
2228 }
2229 static inline ReplacementPart ReplacementSubString(int from, int to) {
2230 ASSERT(from >= 0);
2231 ASSERT(to > from);
2232 return ReplacementPart(-from, to);
2233 }
2234
2235 // If tag <= 0 then it is the negation of a start index of a substring of
2236 // the replacement pattern, otherwise it's a value from PartType.
2237 ReplacementPart(int tag, int data)
2238 : tag(tag), data(data) {
2239 // Must be non-positive or a PartType value.
2240 ASSERT(tag < NUMBER_OF_PART_TYPES);
2241 }
2242 // Either a value of PartType or a non-positive number that is
2243 // the negation of an index into the replacement string.
2244 int tag;
2245 // The data value's interpretation depends on the value of tag:
2246 // tag == SUBJECT_PREFIX ||
2247 // tag == SUBJECT_SUFFIX: data is unused.
2248 // tag == SUBJECT_CAPTURE: data is the number of the capture.
2249 // tag == REPLACEMENT_SUBSTRING ||
2250 // tag == REPLACEMENT_STRING: data is index into array of substrings
2251 // of the replacement string.
2252 // tag <= 0: Temporary representation of the substring of the replacement
2253 // string ranging over -tag .. data.
2254 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
2255 // substring objects.
2256 int data;
2257 };
2258
2259 template<typename Char>
2260 static void ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
2261 Vector<Char> characters,
2262 int capture_count,
2263 int subject_length) {
2264 int length = characters.length();
2265 int last = 0;
2266 for (int i = 0; i < length; i++) {
2267 Char c = characters[i];
2268 if (c == '$') {
2269 int next_index = i + 1;
2270 if (next_index == length) { // No next character!
2271 break;
2272 }
2273 Char c2 = characters[next_index];
2274 switch (c2) {
2275 case '$':
2276 if (i > last) {
2277 // There is a substring before. Include the first "$".
2278 parts->Add(ReplacementPart::ReplacementSubString(last, next_index));
2279 last = next_index + 1; // Continue after the second "$".
2280 } else {
2281 // Let the next substring start with the second "$".
2282 last = next_index;
2283 }
2284 i = next_index;
2285 break;
2286 case '`':
2287 if (i > last) {
2288 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2289 }
2290 parts->Add(ReplacementPart::SubjectPrefix());
2291 i = next_index;
2292 last = i + 1;
2293 break;
2294 case '\'':
2295 if (i > last) {
2296 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2297 }
2298 parts->Add(ReplacementPart::SubjectSuffix(subject_length));
2299 i = next_index;
2300 last = i + 1;
2301 break;
2302 case '&':
2303 if (i > last) {
2304 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2305 }
2306 parts->Add(ReplacementPart::SubjectMatch());
2307 i = next_index;
2308 last = i + 1;
2309 break;
2310 case '0':
2311 case '1':
2312 case '2':
2313 case '3':
2314 case '4':
2315 case '5':
2316 case '6':
2317 case '7':
2318 case '8':
2319 case '9': {
2320 int capture_ref = c2 - '0';
2321 if (capture_ref > capture_count) {
2322 i = next_index;
2323 continue;
2324 }
2325 int second_digit_index = next_index + 1;
2326 if (second_digit_index < length) {
2327 // Peek ahead to see if we have two digits.
2328 Char c3 = characters[second_digit_index];
2329 if ('0' <= c3 && c3 <= '9') { // Double digits.
2330 int double_digit_ref = capture_ref * 10 + c3 - '0';
2331 if (double_digit_ref <= capture_count) {
2332 next_index = second_digit_index;
2333 capture_ref = double_digit_ref;
2334 }
2335 }
2336 }
2337 if (capture_ref > 0) {
2338 if (i > last) {
2339 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2340 }
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002341 ASSERT(capture_ref <= capture_count);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002342 parts->Add(ReplacementPart::SubjectCapture(capture_ref));
2343 last = next_index + 1;
2344 }
2345 i = next_index;
2346 break;
2347 }
2348 default:
2349 i = next_index;
2350 break;
2351 }
2352 }
2353 }
2354 if (length > last) {
2355 if (last == 0) {
2356 parts->Add(ReplacementPart::ReplacementString());
2357 } else {
2358 parts->Add(ReplacementPart::ReplacementSubString(last, length));
2359 }
2360 }
2361 }
2362
2363 ZoneList<ReplacementPart> parts_;
2364 ZoneList<Handle<String> > replacement_substrings_;
2365};
2366
2367
2368void CompiledReplacement::Compile(Handle<String> replacement,
2369 int capture_count,
2370 int subject_length) {
2371 ASSERT(replacement->IsFlat());
ager@chromium.org5ec48922009-05-05 07:25:34 +00002372 if (replacement->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002373 AssertNoAllocation no_alloc;
2374 ParseReplacementPattern(&parts_,
2375 replacement->ToAsciiVector(),
2376 capture_count,
2377 subject_length);
2378 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00002379 ASSERT(replacement->IsTwoByteRepresentation());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002380 AssertNoAllocation no_alloc;
2381
2382 ParseReplacementPattern(&parts_,
2383 replacement->ToUC16Vector(),
2384 capture_count,
2385 subject_length);
2386 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002387 // Find substrings of replacement string and create them as String objects.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002388 int substring_index = 0;
2389 for (int i = 0, n = parts_.length(); i < n; i++) {
2390 int tag = parts_[i].tag;
2391 if (tag <= 0) { // A replacement string slice.
2392 int from = -tag;
2393 int to = parts_[i].data;
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002394 replacement_substrings_.Add(Factory::NewSubString(replacement, from, to));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002395 parts_[i].tag = REPLACEMENT_SUBSTRING;
2396 parts_[i].data = substring_index;
2397 substring_index++;
2398 } else if (tag == REPLACEMENT_STRING) {
2399 replacement_substrings_.Add(replacement);
2400 parts_[i].data = substring_index;
2401 substring_index++;
2402 }
2403 }
2404}
2405
2406
2407void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
2408 int match_from,
2409 int match_to,
2410 Handle<JSArray> last_match_info) {
2411 for (int i = 0, n = parts_.length(); i < n; i++) {
2412 ReplacementPart part = parts_[i];
2413 switch (part.tag) {
2414 case SUBJECT_PREFIX:
2415 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
2416 break;
2417 case SUBJECT_SUFFIX: {
2418 int subject_length = part.data;
2419 if (match_to < subject_length) {
2420 builder->AddSubjectSlice(match_to, subject_length);
2421 }
2422 break;
2423 }
2424 case SUBJECT_CAPTURE: {
2425 int capture = part.data;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002426 FixedArray* match_info = FixedArray::cast(last_match_info->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002427 int from = RegExpImpl::GetCapture(match_info, capture * 2);
2428 int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1);
2429 if (from >= 0 && to > from) {
2430 builder->AddSubjectSlice(from, to);
2431 }
2432 break;
2433 }
2434 case REPLACEMENT_SUBSTRING:
2435 case REPLACEMENT_STRING:
2436 builder->AddString(replacement_substrings_[part.data]);
2437 break;
2438 default:
2439 UNREACHABLE();
2440 }
2441 }
2442}
2443
2444
2445
lrn@chromium.org303ada72010-10-27 09:33:13 +00002446MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
2447 String* subject,
2448 JSRegExp* regexp,
2449 String* replacement,
2450 JSArray* last_match_info) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002451 ASSERT(subject->IsFlat());
2452 ASSERT(replacement->IsFlat());
2453
2454 HandleScope handles;
2455
2456 int length = subject->length();
2457 Handle<String> subject_handle(subject);
2458 Handle<JSRegExp> regexp_handle(regexp);
2459 Handle<String> replacement_handle(replacement);
2460 Handle<JSArray> last_match_info_handle(last_match_info);
2461 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2462 subject_handle,
2463 0,
2464 last_match_info_handle);
2465 if (match.is_null()) {
2466 return Failure::Exception();
2467 }
2468 if (match->IsNull()) {
2469 return *subject_handle;
2470 }
2471
2472 int capture_count = regexp_handle->CaptureCount();
2473
2474 // CompiledReplacement uses zone allocation.
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00002475 CompilationZoneScope zone(DELETE_ON_EXIT);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002476 CompiledReplacement compiled_replacement;
2477 compiled_replacement.Compile(replacement_handle,
2478 capture_count,
2479 length);
2480
2481 bool is_global = regexp_handle->GetFlags().is_global();
2482
2483 // Guessing the number of parts that the final result string is built
2484 // from. Global regexps can match any number of times, so we guess
2485 // conservatively.
2486 int expected_parts =
2487 (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1;
2488 ReplacementStringBuilder builder(subject_handle, expected_parts);
2489
2490 // Index of end of last match.
2491 int prev = 0;
2492
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002493 // Number of parts added by compiled replacement plus preceeding
2494 // string and possibly suffix after last match. It is possible for
2495 // all components to use two elements when encoded as two smis.
2496 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002497 bool matched = true;
2498 do {
2499 ASSERT(last_match_info_handle->HasFastElements());
2500 // Increase the capacity of the builder before entering local handle-scope,
2501 // so its internal buffer can safely allocate a new handle if it grows.
2502 builder.EnsureCapacity(parts_added_per_loop);
2503
2504 HandleScope loop_scope;
2505 int start, end;
2506 {
2507 AssertNoAllocation match_info_array_is_not_in_a_handle;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002508 FixedArray* match_info_array =
2509 FixedArray::cast(last_match_info_handle->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002510
2511 ASSERT_EQ(capture_count * 2 + 2,
2512 RegExpImpl::GetLastCaptureCount(match_info_array));
2513 start = RegExpImpl::GetCapture(match_info_array, 0);
2514 end = RegExpImpl::GetCapture(match_info_array, 1);
2515 }
2516
2517 if (prev < start) {
2518 builder.AddSubjectSlice(prev, start);
2519 }
2520 compiled_replacement.Apply(&builder,
2521 start,
2522 end,
2523 last_match_info_handle);
2524 prev = end;
2525
2526 // Only continue checking for global regexps.
2527 if (!is_global) break;
2528
2529 // Continue from where the match ended, unless it was an empty match.
2530 int next = end;
2531 if (start == end) {
2532 next = end + 1;
2533 if (next > length) break;
2534 }
2535
2536 match = RegExpImpl::Exec(regexp_handle,
2537 subject_handle,
2538 next,
2539 last_match_info_handle);
2540 if (match.is_null()) {
2541 return Failure::Exception();
2542 }
2543 matched = !match->IsNull();
2544 } while (matched);
2545
2546 if (prev < length) {
2547 builder.AddSubjectSlice(prev, length);
2548 }
2549
2550 return *(builder.ToString());
2551}
2552
2553
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002554template <typename ResultSeqString>
lrn@chromium.org303ada72010-10-27 09:33:13 +00002555MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
2556 String* subject,
2557 JSRegExp* regexp,
2558 JSArray* last_match_info) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002559 ASSERT(subject->IsFlat());
2560
2561 HandleScope handles;
2562
2563 Handle<String> subject_handle(subject);
2564 Handle<JSRegExp> regexp_handle(regexp);
2565 Handle<JSArray> last_match_info_handle(last_match_info);
2566 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2567 subject_handle,
2568 0,
2569 last_match_info_handle);
2570 if (match.is_null()) return Failure::Exception();
2571 if (match->IsNull()) return *subject_handle;
2572
2573 ASSERT(last_match_info_handle->HasFastElements());
2574
2575 HandleScope loop_scope;
2576 int start, end;
2577 {
2578 AssertNoAllocation match_info_array_is_not_in_a_handle;
2579 FixedArray* match_info_array =
2580 FixedArray::cast(last_match_info_handle->elements());
2581
2582 start = RegExpImpl::GetCapture(match_info_array, 0);
2583 end = RegExpImpl::GetCapture(match_info_array, 1);
2584 }
2585
2586 int length = subject->length();
2587 int new_length = length - (end - start);
2588 if (new_length == 0) {
2589 return Heap::empty_string();
2590 }
2591 Handle<ResultSeqString> answer;
2592 if (ResultSeqString::kHasAsciiEncoding) {
2593 answer =
2594 Handle<ResultSeqString>::cast(Factory::NewRawAsciiString(new_length));
2595 } else {
2596 answer =
2597 Handle<ResultSeqString>::cast(Factory::NewRawTwoByteString(new_length));
2598 }
2599
2600 // If the regexp isn't global, only match once.
2601 if (!regexp_handle->GetFlags().is_global()) {
2602 if (start > 0) {
2603 String::WriteToFlat(*subject_handle,
2604 answer->GetChars(),
2605 0,
2606 start);
2607 }
2608 if (end < length) {
2609 String::WriteToFlat(*subject_handle,
2610 answer->GetChars() + start,
2611 end,
2612 length);
2613 }
2614 return *answer;
2615 }
2616
2617 int prev = 0; // Index of end of last match.
2618 int next = 0; // Start of next search (prev unless last match was empty).
2619 int position = 0;
2620
2621 do {
2622 if (prev < start) {
2623 // Add substring subject[prev;start] to answer string.
2624 String::WriteToFlat(*subject_handle,
2625 answer->GetChars() + position,
2626 prev,
2627 start);
2628 position += start - prev;
2629 }
2630 prev = end;
2631 next = end;
2632 // Continue from where the match ended, unless it was an empty match.
2633 if (start == end) {
2634 next++;
2635 if (next > length) break;
2636 }
2637 match = RegExpImpl::Exec(regexp_handle,
2638 subject_handle,
2639 next,
2640 last_match_info_handle);
2641 if (match.is_null()) return Failure::Exception();
2642 if (match->IsNull()) break;
2643
2644 ASSERT(last_match_info_handle->HasFastElements());
2645 HandleScope loop_scope;
2646 {
2647 AssertNoAllocation match_info_array_is_not_in_a_handle;
2648 FixedArray* match_info_array =
2649 FixedArray::cast(last_match_info_handle->elements());
2650 start = RegExpImpl::GetCapture(match_info_array, 0);
2651 end = RegExpImpl::GetCapture(match_info_array, 1);
2652 }
2653 } while (true);
2654
2655 if (prev < length) {
2656 // Add substring subject[prev;length] to answer string.
2657 String::WriteToFlat(*subject_handle,
2658 answer->GetChars() + position,
2659 prev,
2660 length);
2661 position += length - prev;
2662 }
2663
2664 if (position == 0) {
2665 return Heap::empty_string();
2666 }
2667
2668 // Shorten string and fill
2669 int string_size = ResultSeqString::SizeFor(position);
2670 int allocated_string_size = ResultSeqString::SizeFor(new_length);
2671 int delta = allocated_string_size - string_size;
2672
2673 answer->set_length(position);
2674 if (delta == 0) return *answer;
2675
2676 Address end_of_string = answer->address() + string_size;
2677 Heap::CreateFillerObjectAt(end_of_string, delta);
2678
2679 return *answer;
2680}
2681
2682
lrn@chromium.org303ada72010-10-27 09:33:13 +00002683static MaybeObject* Runtime_StringReplaceRegExpWithString(Arguments args) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002684 ASSERT(args.length() == 4);
2685
2686 CONVERT_CHECKED(String, subject, args[0]);
2687 if (!subject->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002688 Object* flat_subject;
2689 { MaybeObject* maybe_flat_subject = subject->TryFlatten();
2690 if (!maybe_flat_subject->ToObject(&flat_subject)) {
2691 return maybe_flat_subject;
2692 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002693 }
2694 subject = String::cast(flat_subject);
2695 }
2696
2697 CONVERT_CHECKED(String, replacement, args[2]);
2698 if (!replacement->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002699 Object* flat_replacement;
2700 { MaybeObject* maybe_flat_replacement = replacement->TryFlatten();
2701 if (!maybe_flat_replacement->ToObject(&flat_replacement)) {
2702 return maybe_flat_replacement;
2703 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002704 }
2705 replacement = String::cast(flat_replacement);
2706 }
2707
2708 CONVERT_CHECKED(JSRegExp, regexp, args[1]);
2709 CONVERT_CHECKED(JSArray, last_match_info, args[3]);
2710
2711 ASSERT(last_match_info->HasFastElements());
2712
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002713 if (replacement->length() == 0) {
2714 if (subject->HasOnlyAsciiChars()) {
2715 return StringReplaceRegExpWithEmptyString<SeqAsciiString>(
2716 subject, regexp, last_match_info);
2717 } else {
2718 return StringReplaceRegExpWithEmptyString<SeqTwoByteString>(
2719 subject, regexp, last_match_info);
2720 }
2721 }
2722
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002723 return StringReplaceRegExpWithString(subject,
2724 regexp,
2725 replacement,
2726 last_match_info);
2727}
2728
2729
ager@chromium.org7c537e22008-10-16 08:43:32 +00002730// Perform string match of pattern on subject, starting at start index.
2731// Caller must ensure that 0 <= start_index <= sub->length(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002732// and should check that pat->length() + start_index <= sub->length().
ager@chromium.org7c537e22008-10-16 08:43:32 +00002733int Runtime::StringMatch(Handle<String> sub,
2734 Handle<String> pat,
2735 int start_index) {
2736 ASSERT(0 <= start_index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002737 ASSERT(start_index <= sub->length());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002738
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00002739 int pattern_length = pat->length();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002740 if (pattern_length == 0) return start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002741
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002742 int subject_length = sub->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00002743 if (start_index + pattern_length > subject_length) return -1;
2744
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002745 if (!sub->IsFlat()) FlattenString(sub);
2746 if (!pat->IsFlat()) FlattenString(pat);
ager@chromium.org236ad962008-09-25 09:45:57 +00002747
ager@chromium.org7c537e22008-10-16 08:43:32 +00002748 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002749 // Extract flattened substrings of cons strings before determining asciiness.
2750 String* seq_sub = *sub;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002751 if (seq_sub->IsConsString()) seq_sub = ConsString::cast(seq_sub)->first();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002752 String* seq_pat = *pat;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002753 if (seq_pat->IsConsString()) seq_pat = ConsString::cast(seq_pat)->first();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002754
ager@chromium.org7c537e22008-10-16 08:43:32 +00002755 // dispatch on type of strings
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002756 if (seq_pat->IsAsciiRepresentation()) {
2757 Vector<const char> pat_vector = seq_pat->ToAsciiVector();
2758 if (seq_sub->IsAsciiRepresentation()) {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002759 return SearchString(seq_sub->ToAsciiVector(), pat_vector, start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00002760 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002761 return SearchString(seq_sub->ToUC16Vector(), pat_vector, start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00002762 }
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002763 Vector<const uc16> pat_vector = seq_pat->ToUC16Vector();
2764 if (seq_sub->IsAsciiRepresentation()) {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002765 return SearchString(seq_sub->ToAsciiVector(), pat_vector, start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002766 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002767 return SearchString(seq_sub->ToUC16Vector(), pat_vector, start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002768}
2769
2770
lrn@chromium.org303ada72010-10-27 09:33:13 +00002771static MaybeObject* Runtime_StringIndexOf(Arguments args) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00002772 HandleScope scope; // create a new handle scope
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002773 ASSERT(args.length() == 3);
2774
ager@chromium.org7c537e22008-10-16 08:43:32 +00002775 CONVERT_ARG_CHECKED(String, sub, 0);
2776 CONVERT_ARG_CHECKED(String, pat, 1);
2777
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002778 Object* index = args[2];
2779 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002780 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002781
ager@chromium.org870a0b62008-11-04 11:43:05 +00002782 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
ager@chromium.org7c537e22008-10-16 08:43:32 +00002783 int position = Runtime::StringMatch(sub, pat, start_index);
2784 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002785}
2786
2787
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002788template <typename schar, typename pchar>
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002789static int StringMatchBackwards(Vector<const schar> subject,
2790 Vector<const pchar> pattern,
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002791 int idx) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002792 int pattern_length = pattern.length();
2793 ASSERT(pattern_length >= 1);
2794 ASSERT(idx + pattern_length <= subject.length());
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002795
2796 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002797 for (int i = 0; i < pattern_length; i++) {
2798 uc16 c = pattern[i];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002799 if (c > String::kMaxAsciiCharCode) {
2800 return -1;
2801 }
2802 }
2803 }
2804
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002805 pchar pattern_first_char = pattern[0];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002806 for (int i = idx; i >= 0; i--) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002807 if (subject[i] != pattern_first_char) continue;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002808 int j = 1;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002809 while (j < pattern_length) {
2810 if (pattern[j] != subject[i+j]) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002811 break;
2812 }
2813 j++;
2814 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002815 if (j == pattern_length) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002816 return i;
2817 }
2818 }
2819 return -1;
2820}
2821
lrn@chromium.org303ada72010-10-27 09:33:13 +00002822static MaybeObject* Runtime_StringLastIndexOf(Arguments args) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002823 HandleScope scope; // create a new handle scope
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002824 ASSERT(args.length() == 3);
2825
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002826 CONVERT_ARG_CHECKED(String, sub, 0);
2827 CONVERT_ARG_CHECKED(String, pat, 1);
2828
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002829 Object* index = args[2];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002830 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002831 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002832
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002833 uint32_t pat_length = pat->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002834 uint32_t sub_length = sub->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002835
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002836 if (start_index + pat_length > sub_length) {
2837 start_index = sub_length - pat_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +00002838 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002839
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002840 if (pat_length == 0) {
2841 return Smi::FromInt(start_index);
2842 }
2843
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002844 if (!sub->IsFlat()) FlattenString(sub);
2845 if (!pat->IsFlat()) FlattenString(pat);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002846
2847 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
2848
2849 int position = -1;
2850
2851 if (pat->IsAsciiRepresentation()) {
2852 Vector<const char> pat_vector = pat->ToAsciiVector();
2853 if (sub->IsAsciiRepresentation()) {
2854 position = StringMatchBackwards(sub->ToAsciiVector(),
2855 pat_vector,
2856 start_index);
2857 } else {
2858 position = StringMatchBackwards(sub->ToUC16Vector(),
2859 pat_vector,
2860 start_index);
2861 }
2862 } else {
2863 Vector<const uc16> pat_vector = pat->ToUC16Vector();
2864 if (sub->IsAsciiRepresentation()) {
2865 position = StringMatchBackwards(sub->ToAsciiVector(),
2866 pat_vector,
2867 start_index);
2868 } else {
2869 position = StringMatchBackwards(sub->ToUC16Vector(),
2870 pat_vector,
2871 start_index);
2872 }
2873 }
2874
2875 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002876}
2877
2878
lrn@chromium.org303ada72010-10-27 09:33:13 +00002879static MaybeObject* Runtime_StringLocaleCompare(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002880 NoHandleAllocation ha;
2881 ASSERT(args.length() == 2);
2882
2883 CONVERT_CHECKED(String, str1, args[0]);
2884 CONVERT_CHECKED(String, str2, args[1]);
2885
2886 if (str1 == str2) return Smi::FromInt(0); // Equal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002887 int str1_length = str1->length();
2888 int str2_length = str2->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002889
2890 // Decide trivial cases without flattening.
2891 if (str1_length == 0) {
2892 if (str2_length == 0) return Smi::FromInt(0); // Equal.
2893 return Smi::FromInt(-str2_length);
2894 } else {
2895 if (str2_length == 0) return Smi::FromInt(str1_length);
2896 }
2897
2898 int end = str1_length < str2_length ? str1_length : str2_length;
2899
2900 // No need to flatten if we are going to find the answer on the first
2901 // character. At this point we know there is at least one character
2902 // in each string, due to the trivial case handling above.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002903 int d = str1->Get(0) - str2->Get(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002904 if (d != 0) return Smi::FromInt(d);
2905
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002906 str1->TryFlatten();
2907 str2->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002908
2909 static StringInputBuffer buf1;
2910 static StringInputBuffer buf2;
2911
2912 buf1.Reset(str1);
2913 buf2.Reset(str2);
2914
2915 for (int i = 0; i < end; i++) {
2916 uint16_t char1 = buf1.GetNext();
2917 uint16_t char2 = buf2.GetNext();
2918 if (char1 != char2) return Smi::FromInt(char1 - char2);
2919 }
2920
2921 return Smi::FromInt(str1_length - str2_length);
2922}
2923
2924
lrn@chromium.org303ada72010-10-27 09:33:13 +00002925static MaybeObject* Runtime_SubString(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002926 NoHandleAllocation ha;
2927 ASSERT(args.length() == 3);
2928
2929 CONVERT_CHECKED(String, value, args[0]);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002930 Object* from = args[1];
2931 Object* to = args[2];
2932 int start, end;
2933 // We have a fast integer-only case here to avoid a conversion to double in
2934 // the common case where from and to are Smis.
2935 if (from->IsSmi() && to->IsSmi()) {
2936 start = Smi::cast(from)->value();
2937 end = Smi::cast(to)->value();
2938 } else {
2939 CONVERT_DOUBLE_CHECKED(from_number, from);
2940 CONVERT_DOUBLE_CHECKED(to_number, to);
2941 start = FastD2I(from_number);
2942 end = FastD2I(to_number);
2943 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002944 RUNTIME_ASSERT(end >= start);
2945 RUNTIME_ASSERT(start >= 0);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00002946 RUNTIME_ASSERT(end <= value->length());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002947 Counters::sub_string_runtime.Increment();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002948 return value->SubString(start, end);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002949}
2950
2951
lrn@chromium.org303ada72010-10-27 09:33:13 +00002952static MaybeObject* Runtime_StringMatch(Arguments args) {
ager@chromium.org41826e72009-03-30 13:30:57 +00002953 ASSERT_EQ(3, args.length());
2954
2955 CONVERT_ARG_CHECKED(String, subject, 0);
2956 CONVERT_ARG_CHECKED(JSRegExp, regexp, 1);
2957 CONVERT_ARG_CHECKED(JSArray, regexp_info, 2);
2958 HandleScope handles;
2959
2960 Handle<Object> match = RegExpImpl::Exec(regexp, subject, 0, regexp_info);
2961
2962 if (match.is_null()) {
2963 return Failure::Exception();
2964 }
2965 if (match->IsNull()) {
2966 return Heap::null_value();
2967 }
2968 int length = subject->length();
2969
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00002970 CompilationZoneScope zone_space(DELETE_ON_EXIT);
ager@chromium.org41826e72009-03-30 13:30:57 +00002971 ZoneList<int> offsets(8);
2972 do {
2973 int start;
2974 int end;
2975 {
2976 AssertNoAllocation no_alloc;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002977 FixedArray* elements = FixedArray::cast(regexp_info->elements());
ager@chromium.org41826e72009-03-30 13:30:57 +00002978 start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value();
2979 end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value();
2980 }
2981 offsets.Add(start);
2982 offsets.Add(end);
2983 int index = start < end ? end : end + 1;
2984 if (index > length) break;
2985 match = RegExpImpl::Exec(regexp, subject, index, regexp_info);
2986 if (match.is_null()) {
2987 return Failure::Exception();
2988 }
2989 } while (!match->IsNull());
2990 int matches = offsets.length() / 2;
2991 Handle<FixedArray> elements = Factory::NewFixedArray(matches);
2992 for (int i = 0; i < matches ; i++) {
2993 int from = offsets.at(i * 2);
2994 int to = offsets.at(i * 2 + 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002995 Handle<String> match = Factory::NewSubString(subject, from, to);
2996 elements->set(i, *match);
ager@chromium.org41826e72009-03-30 13:30:57 +00002997 }
2998 Handle<JSArray> result = Factory::NewJSArrayWithElements(elements);
2999 result->set_length(Smi::FromInt(matches));
3000 return *result;
3001}
3002
3003
lrn@chromium.org25156de2010-04-06 13:10:27 +00003004// Two smis before and after the match, for very long strings.
3005const int kMaxBuilderEntriesPerRegExpMatch = 5;
3006
3007
3008static void SetLastMatchInfoNoCaptures(Handle<String> subject,
3009 Handle<JSArray> last_match_info,
3010 int match_start,
3011 int match_end) {
3012 // Fill last_match_info with a single capture.
3013 last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead);
3014 AssertNoAllocation no_gc;
3015 FixedArray* elements = FixedArray::cast(last_match_info->elements());
3016 RegExpImpl::SetLastCaptureCount(elements, 2);
3017 RegExpImpl::SetLastInput(elements, *subject);
3018 RegExpImpl::SetLastSubject(elements, *subject);
3019 RegExpImpl::SetCapture(elements, 0, match_start);
3020 RegExpImpl::SetCapture(elements, 1, match_end);
3021}
3022
3023
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003024template <typename SubjectChar, typename PatternChar>
3025static bool SearchStringMultiple(Vector<const SubjectChar> subject,
3026 Vector<const PatternChar> pattern,
3027 String* pattern_string,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003028 FixedArrayBuilder* builder,
3029 int* match_pos) {
3030 int pos = *match_pos;
3031 int subject_length = subject.length();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003032 int pattern_length = pattern.length();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003033 int max_search_start = subject_length - pattern_length;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003034 StringSearch<PatternChar, SubjectChar> search(pattern);
3035 while (pos <= max_search_start) {
3036 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
3037 *match_pos = pos;
3038 return false;
3039 }
3040 // Position of end of previous match.
3041 int match_end = pos + pattern_length;
3042 int new_pos = search.Search(subject, match_end);
3043 if (new_pos >= 0) {
3044 // A match.
3045 if (new_pos > match_end) {
3046 ReplacementStringBuilder::AddSubjectSlice(builder,
3047 match_end,
3048 new_pos);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003049 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003050 pos = new_pos;
3051 builder->Add(pattern_string);
3052 } else {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003053 break;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003054 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003055 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003056
lrn@chromium.org25156de2010-04-06 13:10:27 +00003057 if (pos < max_search_start) {
3058 ReplacementStringBuilder::AddSubjectSlice(builder,
3059 pos + pattern_length,
3060 subject_length);
3061 }
3062 *match_pos = pos;
3063 return true;
3064}
3065
3066
3067static bool SearchStringMultiple(Handle<String> subject,
3068 Handle<String> pattern,
3069 Handle<JSArray> last_match_info,
3070 FixedArrayBuilder* builder) {
3071 ASSERT(subject->IsFlat());
3072 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003073
3074 // Treating as if a previous match was before first character.
3075 int match_pos = -pattern->length();
3076
3077 for (;;) { // Break when search complete.
3078 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3079 AssertNoAllocation no_gc;
3080 if (subject->IsAsciiRepresentation()) {
3081 Vector<const char> subject_vector = subject->ToAsciiVector();
3082 if (pattern->IsAsciiRepresentation()) {
3083 if (SearchStringMultiple(subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003084 pattern->ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003085 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003086 builder,
3087 &match_pos)) break;
3088 } else {
3089 if (SearchStringMultiple(subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003090 pattern->ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003091 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003092 builder,
3093 &match_pos)) break;
3094 }
3095 } else {
3096 Vector<const uc16> subject_vector = subject->ToUC16Vector();
3097 if (pattern->IsAsciiRepresentation()) {
3098 if (SearchStringMultiple(subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003099 pattern->ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003100 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003101 builder,
3102 &match_pos)) break;
3103 } else {
3104 if (SearchStringMultiple(subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003105 pattern->ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003106 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003107 builder,
3108 &match_pos)) break;
3109 }
3110 }
3111 }
3112
3113 if (match_pos >= 0) {
3114 SetLastMatchInfoNoCaptures(subject,
3115 last_match_info,
3116 match_pos,
3117 match_pos + pattern->length());
3118 return true;
3119 }
3120 return false; // No matches at all.
3121}
3122
3123
3124static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple(
3125 Handle<String> subject,
3126 Handle<JSRegExp> regexp,
3127 Handle<JSArray> last_match_array,
3128 FixedArrayBuilder* builder) {
3129 ASSERT(subject->IsFlat());
3130 int match_start = -1;
3131 int match_end = 0;
3132 int pos = 0;
3133 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3134 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3135
3136 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003137 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003138 int subject_length = subject->length();
3139
3140 for (;;) { // Break on failure, return on exception.
3141 RegExpImpl::IrregexpResult result =
3142 RegExpImpl::IrregexpExecOnce(regexp,
3143 subject,
3144 pos,
3145 register_vector);
3146 if (result == RegExpImpl::RE_SUCCESS) {
3147 match_start = register_vector[0];
3148 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3149 if (match_end < match_start) {
3150 ReplacementStringBuilder::AddSubjectSlice(builder,
3151 match_end,
3152 match_start);
3153 }
3154 match_end = register_vector[1];
3155 HandleScope loop_scope;
3156 builder->Add(*Factory::NewSubString(subject, match_start, match_end));
3157 if (match_start != match_end) {
3158 pos = match_end;
3159 } else {
3160 pos = match_end + 1;
3161 if (pos > subject_length) break;
3162 }
3163 } else if (result == RegExpImpl::RE_FAILURE) {
3164 break;
3165 } else {
3166 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3167 return result;
3168 }
3169 }
3170
3171 if (match_start >= 0) {
3172 if (match_end < subject_length) {
3173 ReplacementStringBuilder::AddSubjectSlice(builder,
3174 match_end,
3175 subject_length);
3176 }
3177 SetLastMatchInfoNoCaptures(subject,
3178 last_match_array,
3179 match_start,
3180 match_end);
3181 return RegExpImpl::RE_SUCCESS;
3182 } else {
3183 return RegExpImpl::RE_FAILURE; // No matches at all.
3184 }
3185}
3186
3187
3188static RegExpImpl::IrregexpResult SearchRegExpMultiple(
3189 Handle<String> subject,
3190 Handle<JSRegExp> regexp,
3191 Handle<JSArray> last_match_array,
3192 FixedArrayBuilder* builder) {
3193
3194 ASSERT(subject->IsFlat());
3195 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3196 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3197
3198 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003199 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003200
3201 RegExpImpl::IrregexpResult result =
3202 RegExpImpl::IrregexpExecOnce(regexp,
3203 subject,
3204 0,
3205 register_vector);
3206
3207 int capture_count = regexp->CaptureCount();
3208 int subject_length = subject->length();
3209
3210 // Position to search from.
3211 int pos = 0;
3212 // End of previous match. Differs from pos if match was empty.
3213 int match_end = 0;
3214 if (result == RegExpImpl::RE_SUCCESS) {
3215 // Need to keep a copy of the previous match for creating last_match_info
3216 // at the end, so we have two vectors that we swap between.
3217 OffsetsVector registers2(required_registers);
3218 Vector<int> prev_register_vector(registers2.vector(), registers2.length());
3219
3220 do {
3221 int match_start = register_vector[0];
3222 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3223 if (match_end < match_start) {
3224 ReplacementStringBuilder::AddSubjectSlice(builder,
3225 match_end,
3226 match_start);
3227 }
3228 match_end = register_vector[1];
3229
3230 {
3231 // Avoid accumulating new handles inside loop.
3232 HandleScope temp_scope;
3233 // Arguments array to replace function is match, captures, index and
3234 // subject, i.e., 3 + capture count in total.
3235 Handle<FixedArray> elements = Factory::NewFixedArray(3 + capture_count);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003236 Handle<String> match = Factory::NewSubString(subject,
3237 match_start,
3238 match_end);
3239 elements->set(0, *match);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003240 for (int i = 1; i <= capture_count; i++) {
3241 int start = register_vector[i * 2];
3242 if (start >= 0) {
3243 int end = register_vector[i * 2 + 1];
3244 ASSERT(start <= end);
3245 Handle<String> substring = Factory::NewSubString(subject,
3246 start,
3247 end);
3248 elements->set(i, *substring);
3249 } else {
3250 ASSERT(register_vector[i * 2 + 1] < 0);
3251 elements->set(i, Heap::undefined_value());
3252 }
3253 }
3254 elements->set(capture_count + 1, Smi::FromInt(match_start));
3255 elements->set(capture_count + 2, *subject);
3256 builder->Add(*Factory::NewJSArrayWithElements(elements));
3257 }
3258 // Swap register vectors, so the last successful match is in
3259 // prev_register_vector.
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003260 Vector<int32_t> tmp = prev_register_vector;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003261 prev_register_vector = register_vector;
3262 register_vector = tmp;
3263
3264 if (match_end > match_start) {
3265 pos = match_end;
3266 } else {
3267 pos = match_end + 1;
3268 if (pos > subject_length) {
3269 break;
3270 }
3271 }
3272
3273 result = RegExpImpl::IrregexpExecOnce(regexp,
3274 subject,
3275 pos,
3276 register_vector);
3277 } while (result == RegExpImpl::RE_SUCCESS);
3278
3279 if (result != RegExpImpl::RE_EXCEPTION) {
3280 // Finished matching, with at least one match.
3281 if (match_end < subject_length) {
3282 ReplacementStringBuilder::AddSubjectSlice(builder,
3283 match_end,
3284 subject_length);
3285 }
3286
3287 int last_match_capture_count = (capture_count + 1) * 2;
3288 int last_match_array_size =
3289 last_match_capture_count + RegExpImpl::kLastMatchOverhead;
3290 last_match_array->EnsureSize(last_match_array_size);
3291 AssertNoAllocation no_gc;
3292 FixedArray* elements = FixedArray::cast(last_match_array->elements());
3293 RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count);
3294 RegExpImpl::SetLastSubject(elements, *subject);
3295 RegExpImpl::SetLastInput(elements, *subject);
3296 for (int i = 0; i < last_match_capture_count; i++) {
3297 RegExpImpl::SetCapture(elements, i, prev_register_vector[i]);
3298 }
3299 return RegExpImpl::RE_SUCCESS;
3300 }
3301 }
3302 // No matches at all, return failure or exception result directly.
3303 return result;
3304}
3305
3306
lrn@chromium.org303ada72010-10-27 09:33:13 +00003307static MaybeObject* Runtime_RegExpExecMultiple(Arguments args) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003308 ASSERT(args.length() == 4);
3309 HandleScope handles;
3310
3311 CONVERT_ARG_CHECKED(String, subject, 1);
3312 if (!subject->IsFlat()) { FlattenString(subject); }
3313 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
3314 CONVERT_ARG_CHECKED(JSArray, last_match_info, 2);
3315 CONVERT_ARG_CHECKED(JSArray, result_array, 3);
3316
3317 ASSERT(last_match_info->HasFastElements());
3318 ASSERT(regexp->GetFlags().is_global());
3319 Handle<FixedArray> result_elements;
3320 if (result_array->HasFastElements()) {
3321 result_elements =
3322 Handle<FixedArray>(FixedArray::cast(result_array->elements()));
3323 } else {
3324 result_elements = Factory::NewFixedArrayWithHoles(16);
3325 }
3326 FixedArrayBuilder builder(result_elements);
3327
3328 if (regexp->TypeTag() == JSRegExp::ATOM) {
3329 Handle<String> pattern(
3330 String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003331 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003332 if (SearchStringMultiple(subject, pattern, last_match_info, &builder)) {
3333 return *builder.ToJSArray(result_array);
3334 }
3335 return Heap::null_value();
3336 }
3337
3338 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
3339
3340 RegExpImpl::IrregexpResult result;
3341 if (regexp->CaptureCount() == 0) {
3342 result = SearchRegExpNoCaptureMultiple(subject,
3343 regexp,
3344 last_match_info,
3345 &builder);
3346 } else {
3347 result = SearchRegExpMultiple(subject, regexp, last_match_info, &builder);
3348 }
3349 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array);
3350 if (result == RegExpImpl::RE_FAILURE) return Heap::null_value();
3351 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3352 return Failure::Exception();
3353}
3354
3355
lrn@chromium.org303ada72010-10-27 09:33:13 +00003356static MaybeObject* Runtime_NumberToRadixString(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003357 NoHandleAllocation ha;
3358 ASSERT(args.length() == 2);
3359
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003360 // Fast case where the result is a one character string.
3361 if (args[0]->IsSmi() && args[1]->IsSmi()) {
3362 int value = Smi::cast(args[0])->value();
3363 int radix = Smi::cast(args[1])->value();
3364 if (value >= 0 && value < radix) {
3365 RUNTIME_ASSERT(radix <= 36);
3366 // Character array used for conversion.
3367 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
3368 return Heap::LookupSingleCharacterStringFromCode(kCharTable[value]);
3369 }
3370 }
3371
3372 // Slow case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003373 CONVERT_DOUBLE_CHECKED(value, args[0]);
3374 if (isnan(value)) {
3375 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
3376 }
3377 if (isinf(value)) {
3378 if (value < 0) {
3379 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
3380 }
3381 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
3382 }
3383 CONVERT_DOUBLE_CHECKED(radix_number, args[1]);
3384 int radix = FastD2I(radix_number);
3385 RUNTIME_ASSERT(2 <= radix && radix <= 36);
3386 char* str = DoubleToRadixCString(value, radix);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003387 MaybeObject* result = Heap::AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003388 DeleteArray(str);
3389 return result;
3390}
3391
3392
lrn@chromium.org303ada72010-10-27 09:33:13 +00003393static MaybeObject* Runtime_NumberToFixed(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003394 NoHandleAllocation ha;
3395 ASSERT(args.length() == 2);
3396
3397 CONVERT_DOUBLE_CHECKED(value, args[0]);
3398 if (isnan(value)) {
3399 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
3400 }
3401 if (isinf(value)) {
3402 if (value < 0) {
3403 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
3404 }
3405 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
3406 }
3407 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3408 int f = FastD2I(f_number);
3409 RUNTIME_ASSERT(f >= 0);
3410 char* str = DoubleToFixedCString(value, f);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003411 MaybeObject* result = Heap::AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003412 DeleteArray(str);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003413 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003414}
3415
3416
lrn@chromium.org303ada72010-10-27 09:33:13 +00003417static MaybeObject* Runtime_NumberToExponential(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003418 NoHandleAllocation ha;
3419 ASSERT(args.length() == 2);
3420
3421 CONVERT_DOUBLE_CHECKED(value, args[0]);
3422 if (isnan(value)) {
3423 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
3424 }
3425 if (isinf(value)) {
3426 if (value < 0) {
3427 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
3428 }
3429 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
3430 }
3431 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3432 int f = FastD2I(f_number);
3433 RUNTIME_ASSERT(f >= -1 && f <= 20);
3434 char* str = DoubleToExponentialCString(value, f);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003435 MaybeObject* result = Heap::AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003436 DeleteArray(str);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003437 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003438}
3439
3440
lrn@chromium.org303ada72010-10-27 09:33:13 +00003441static MaybeObject* Runtime_NumberToPrecision(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003442 NoHandleAllocation ha;
3443 ASSERT(args.length() == 2);
3444
3445 CONVERT_DOUBLE_CHECKED(value, args[0]);
3446 if (isnan(value)) {
3447 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
3448 }
3449 if (isinf(value)) {
3450 if (value < 0) {
3451 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
3452 }
3453 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
3454 }
3455 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3456 int f = FastD2I(f_number);
3457 RUNTIME_ASSERT(f >= 1 && f <= 21);
3458 char* str = DoubleToPrecisionCString(value, f);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003459 MaybeObject* result = Heap::AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003460 DeleteArray(str);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003461 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003462}
3463
3464
3465// Returns a single character string where first character equals
3466// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003467static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003468 if (index < static_cast<uint32_t>(string->length())) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003469 string->TryFlatten();
ager@chromium.org870a0b62008-11-04 11:43:05 +00003470 return LookupSingleCharacterStringFromCode(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003471 string->Get(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003472 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003473 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003474}
3475
3476
lrn@chromium.org303ada72010-10-27 09:33:13 +00003477MaybeObject* Runtime::GetElementOrCharAt(Handle<Object> object,
3478 uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003479 // Handle [] indexing on Strings
3480 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003481 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
3482 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003483 }
3484
3485 // Handle [] indexing on String objects
3486 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003487 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
3488 Handle<Object> result =
3489 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
3490 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003491 }
3492
3493 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003494 Handle<Object> prototype = GetPrototype(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003495 return prototype->GetElement(index);
3496 }
3497
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003498 return GetElement(object, index);
3499}
3500
3501
lrn@chromium.org303ada72010-10-27 09:33:13 +00003502MaybeObject* Runtime::GetElement(Handle<Object> object, uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003503 return object->GetElement(index);
3504}
3505
3506
lrn@chromium.org303ada72010-10-27 09:33:13 +00003507MaybeObject* Runtime::GetObjectProperty(Handle<Object> object,
3508 Handle<Object> key) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003509 HandleScope scope;
3510
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003511 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003512 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003513 Handle<Object> error =
3514 Factory::NewTypeError("non_object_property_load",
3515 HandleVector(args, 2));
3516 return Top::Throw(*error);
3517 }
3518
3519 // Check if the given key is an array index.
3520 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003521 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003522 return GetElementOrCharAt(object, index);
3523 }
3524
3525 // Convert the key to a string - possibly by calling back into JavaScript.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003526 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003527 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003528 name = Handle<String>::cast(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003529 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003530 bool has_pending_exception = false;
3531 Handle<Object> converted =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003532 Execution::ToString(key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003533 if (has_pending_exception) return Failure::Exception();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003534 name = Handle<String>::cast(converted);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003535 }
3536
ager@chromium.org32912102009-01-16 10:38:43 +00003537 // Check if the name is trivially convertible to an index and get
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003538 // the element if so.
3539 if (name->AsArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003540 return GetElementOrCharAt(object, index);
3541 } else {
3542 PropertyAttributes attr;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003543 return object->GetProperty(*name, &attr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003544 }
3545}
3546
3547
lrn@chromium.org303ada72010-10-27 09:33:13 +00003548static MaybeObject* Runtime_GetProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003549 NoHandleAllocation ha;
3550 ASSERT(args.length() == 2);
3551
3552 Handle<Object> object = args.at<Object>(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003553 Handle<Object> key = args.at<Object>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003554
3555 return Runtime::GetObjectProperty(object, key);
3556}
3557
3558
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003559// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003560static MaybeObject* Runtime_KeyedGetProperty(Arguments args) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00003561 NoHandleAllocation ha;
3562 ASSERT(args.length() == 2);
3563
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003564 // Fast cases for getting named properties of the receiver JSObject
ager@chromium.org8bb60582008-12-11 12:02:20 +00003565 // itself.
3566 //
3567 // The global proxy objects has to be excluded since LocalLookup on
ager@chromium.org32912102009-01-16 10:38:43 +00003568 // the global proxy object can return a valid result even though the
ager@chromium.org8bb60582008-12-11 12:02:20 +00003569 // global proxy object never has properties. This is the case
3570 // because the global proxy object forwards everything to its hidden
3571 // prototype including local lookups.
3572 //
3573 // Additionally, we need to make sure that we do not cache results
3574 // for objects that require access checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003575 if (args[0]->IsJSObject() &&
3576 !args[0]->IsJSGlobalProxy() &&
ager@chromium.org8bb60582008-12-11 12:02:20 +00003577 !args[0]->IsAccessCheckNeeded() &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003578 args[1]->IsString()) {
3579 JSObject* receiver = JSObject::cast(args[0]);
3580 String* key = String::cast(args[1]);
3581 if (receiver->HasFastProperties()) {
3582 // Attempt to use lookup cache.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003583 Map* receiver_map = receiver->map();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00003584 int offset = KeyedLookupCache::Lookup(receiver_map, key);
3585 if (offset != -1) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003586 Object* value = receiver->FastPropertyAt(offset);
3587 return value->IsTheHole() ? Heap::undefined_value() : value;
3588 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003589 // Lookup cache miss. Perform lookup and update the cache if appropriate.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003590 LookupResult result;
3591 receiver->LocalLookup(key, &result);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00003592 if (result.IsProperty() && result.type() == FIELD) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003593 int offset = result.GetFieldIndex();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00003594 KeyedLookupCache::Update(receiver_map, key, offset);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003595 return receiver->FastPropertyAt(offset);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003596 }
3597 } else {
3598 // Attempt dictionary lookup.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00003599 StringDictionary* dictionary = receiver->property_dictionary();
3600 int entry = dictionary->FindEntry(key);
3601 if ((entry != StringDictionary::kNotFound) &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003602 (dictionary->DetailsAt(entry).type() == NORMAL)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003603 Object* value = dictionary->ValueAt(entry);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003604 if (!receiver->IsGlobalObject()) return value;
3605 value = JSGlobalPropertyCell::cast(value)->value();
3606 if (!value->IsTheHole()) return value;
3607 // If value is the hole do the general lookup.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003608 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00003609 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003610 } else if (args[0]->IsString() && args[1]->IsSmi()) {
3611 // Fast case for string indexing using [] with a smi index.
3612 HandleScope scope;
3613 Handle<String> str = args.at<String>(0);
3614 int index = Smi::cast(args[1])->value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003615 if (index >= 0 && index < str->length()) {
3616 Handle<Object> result = GetCharAt(str, index);
3617 return *result;
3618 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00003619 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003620
3621 // Fall back to GetObjectProperty.
ager@chromium.org7c537e22008-10-16 08:43:32 +00003622 return Runtime::GetObjectProperty(args.at<Object>(0),
3623 args.at<Object>(1));
3624}
3625
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003626// Implements part of 8.12.9 DefineOwnProperty.
3627// There are 3 cases that lead here:
3628// Step 4b - define a new accessor property.
3629// Steps 9c & 12 - replace an existing data property with an accessor property.
3630// Step 12 - update an existing accessor property with an accessor or generic
3631// descriptor.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003632static MaybeObject* Runtime_DefineOrRedefineAccessorProperty(Arguments args) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003633 ASSERT(args.length() == 5);
3634 HandleScope scope;
3635 CONVERT_ARG_CHECKED(JSObject, obj, 0);
3636 CONVERT_CHECKED(String, name, args[1]);
3637 CONVERT_CHECKED(Smi, flag_setter, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003638 Object* fun = args[3];
3639 RUNTIME_ASSERT(fun->IsJSFunction() || fun->IsUndefined());
ager@chromium.org5c838252010-02-19 08:53:10 +00003640 CONVERT_CHECKED(Smi, flag_attr, args[4]);
3641 int unchecked = flag_attr->value();
3642 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3643 RUNTIME_ASSERT(!obj->IsNull());
3644 LookupResult result;
3645 obj->LocalLookupRealNamedProperty(name, &result);
3646
3647 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
3648 // If an existing property is either FIELD, NORMAL or CONSTANT_FUNCTION
3649 // delete it to avoid running into trouble in DefineAccessor, which
3650 // handles this incorrectly if the property is readonly (does nothing)
3651 if (result.IsProperty() &&
3652 (result.type() == FIELD || result.type() == NORMAL
3653 || result.type() == CONSTANT_FUNCTION)) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003654 Object* ok;
3655 { MaybeObject* maybe_ok =
3656 obj->DeleteProperty(name, JSObject::NORMAL_DELETION);
3657 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
3658 }
ager@chromium.org5c838252010-02-19 08:53:10 +00003659 }
3660 return obj->DefineAccessor(name, flag_setter->value() == 0, fun, attr);
3661}
3662
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003663// Implements part of 8.12.9 DefineOwnProperty.
3664// There are 3 cases that lead here:
3665// Step 4a - define a new data property.
3666// Steps 9b & 12 - replace an existing accessor property with a data property.
3667// Step 12 - update an existing data property with a data or generic
3668// descriptor.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003669static MaybeObject* Runtime_DefineOrRedefineDataProperty(Arguments args) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003670 ASSERT(args.length() == 4);
3671 HandleScope scope;
3672 CONVERT_ARG_CHECKED(JSObject, js_object, 0);
3673 CONVERT_ARG_CHECKED(String, name, 1);
3674 Handle<Object> obj_value = args.at<Object>(2);
3675
3676 CONVERT_CHECKED(Smi, flag, args[3]);
3677 int unchecked = flag->value();
3678 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3679
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003680 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
3681
3682 // Check if this is an element.
3683 uint32_t index;
3684 bool is_element = name->AsArrayIndex(&index);
3685
3686 // Special case for elements if any of the flags are true.
3687 // If elements are in fast case we always implicitly assume that:
3688 // DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
3689 if (((unchecked & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0) &&
3690 is_element) {
3691 // Normalize the elements to enable attributes on the property.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003692 if (js_object->IsJSGlobalProxy()) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003693 // We do not need to do access checks here since these has already
3694 // been performed by the call to GetOwnProperty.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003695 Handle<Object> proto(js_object->GetPrototype());
3696 // If proxy is detached, ignore the assignment. Alternatively,
3697 // we could throw an exception.
3698 if (proto->IsNull()) return *obj_value;
3699 js_object = Handle<JSObject>::cast(proto);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003700 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003701 NormalizeElements(js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003702 Handle<NumberDictionary> dictionary(js_object->element_dictionary());
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003703 // Make sure that we never go back to fast case.
3704 dictionary->set_requires_slow_elements();
3705 PropertyDetails details = PropertyDetails(attr, NORMAL);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003706 NumberDictionarySet(dictionary, index, obj_value, details);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003707 return *obj_value;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003708 }
3709
ager@chromium.org5c838252010-02-19 08:53:10 +00003710 LookupResult result;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003711 js_object->LookupRealNamedProperty(*name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00003712
ager@chromium.org5c838252010-02-19 08:53:10 +00003713 // Take special care when attributes are different and there is already
3714 // a property. For simplicity we normalize the property which enables us
3715 // to not worry about changing the instance_descriptor and creating a new
3716 // map. The current version of SetObjectProperty does not handle attributes
3717 // correctly in the case where a property is a field and is reset with
3718 // new attributes.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003719 if (result.IsProperty() &&
3720 (attr != result.GetAttributes() || result.type() == CALLBACKS)) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003721 // New attributes - normalize to avoid writing to instance descriptor
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003722 if (js_object->IsJSGlobalProxy()) {
3723 // Since the result is a property, the prototype will exist so
3724 // we don't have to check for null.
3725 js_object = Handle<JSObject>(JSObject::cast(js_object->GetPrototype()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003726 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003727 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00003728 // Use IgnoreAttributes version since a readonly property may be
3729 // overridden and SetProperty does not allow this.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003730 return js_object->SetLocalPropertyIgnoreAttributes(*name,
3731 *obj_value,
3732 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00003733 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003734
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003735 return Runtime::ForceSetObjectProperty(js_object, name, obj_value, attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00003736}
3737
3738
lrn@chromium.org303ada72010-10-27 09:33:13 +00003739MaybeObject* Runtime::SetObjectProperty(Handle<Object> object,
3740 Handle<Object> key,
3741 Handle<Object> value,
3742 PropertyAttributes attr) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003743 HandleScope scope;
3744
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003745 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003746 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003747 Handle<Object> error =
3748 Factory::NewTypeError("non_object_property_store",
3749 HandleVector(args, 2));
3750 return Top::Throw(*error);
3751 }
3752
3753 // If the object isn't a JavaScript object, we ignore the store.
3754 if (!object->IsJSObject()) return *value;
3755
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003756 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
3757
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003758 // Check if the given key is an array index.
3759 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003760 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003761 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
3762 // of a string using [] notation. We need to support this too in
3763 // JavaScript.
3764 // In the case of a String object we just need to redirect the assignment to
3765 // the underlying string if the index is in range. Since the underlying
3766 // string does nothing with the assignment then we can ignore such
3767 // assignments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003768 if (js_object->IsStringObjectWithCharacterAt(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003769 return *value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003770 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003771
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003772 Handle<Object> result = SetElement(js_object, index, value);
3773 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003774 return *value;
3775 }
3776
3777 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003778 Handle<Object> result;
3779 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003780 result = SetElement(js_object, index, value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003781 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003782 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003783 key_string->TryFlatten();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003784 result = SetProperty(js_object, key_string, value, attr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003785 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003786 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003787 return *value;
3788 }
3789
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003790 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003791 bool has_pending_exception = false;
3792 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
3793 if (has_pending_exception) return Failure::Exception();
3794 Handle<String> name = Handle<String>::cast(converted);
3795
3796 if (name->AsArrayIndex(&index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003797 return js_object->SetElement(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003798 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003799 return js_object->SetProperty(*name, *value, attr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003800 }
3801}
3802
3803
lrn@chromium.org303ada72010-10-27 09:33:13 +00003804MaybeObject* Runtime::ForceSetObjectProperty(Handle<JSObject> js_object,
3805 Handle<Object> key,
3806 Handle<Object> value,
3807 PropertyAttributes attr) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003808 HandleScope scope;
3809
3810 // Check if the given key is an array index.
3811 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003812 if (key->ToArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003813 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
3814 // of a string using [] notation. We need to support this too in
3815 // JavaScript.
3816 // In the case of a String object we just need to redirect the assignment to
3817 // the underlying string if the index is in range. Since the underlying
3818 // string does nothing with the assignment then we can ignore such
3819 // assignments.
3820 if (js_object->IsStringObjectWithCharacterAt(index)) {
3821 return *value;
3822 }
3823
3824 return js_object->SetElement(index, *value);
3825 }
3826
3827 if (key->IsString()) {
3828 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003829 return js_object->SetElement(index, *value);
3830 } else {
3831 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003832 key_string->TryFlatten();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003833 return js_object->SetLocalPropertyIgnoreAttributes(*key_string,
3834 *value,
3835 attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003836 }
3837 }
3838
3839 // Call-back into JavaScript to convert the key to a string.
3840 bool has_pending_exception = false;
3841 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
3842 if (has_pending_exception) return Failure::Exception();
3843 Handle<String> name = Handle<String>::cast(converted);
3844
3845 if (name->AsArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003846 return js_object->SetElement(index, *value);
3847 } else {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003848 return js_object->SetLocalPropertyIgnoreAttributes(*name, *value, attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003849 }
3850}
3851
3852
lrn@chromium.org303ada72010-10-27 09:33:13 +00003853MaybeObject* Runtime::ForceDeleteObjectProperty(Handle<JSObject> js_object,
3854 Handle<Object> key) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00003855 HandleScope scope;
3856
3857 // Check if the given key is an array index.
3858 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003859 if (key->ToArrayIndex(&index)) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00003860 // In Firefox/SpiderMonkey, Safari and Opera you can access the
3861 // characters of a string using [] notation. In the case of a
3862 // String object we just need to redirect the deletion to the
3863 // underlying string if the index is in range. Since the
3864 // underlying string does nothing with the deletion, we can ignore
3865 // such deletions.
3866 if (js_object->IsStringObjectWithCharacterAt(index)) {
3867 return Heap::true_value();
3868 }
3869
3870 return js_object->DeleteElement(index, JSObject::FORCE_DELETION);
3871 }
3872
3873 Handle<String> key_string;
3874 if (key->IsString()) {
3875 key_string = Handle<String>::cast(key);
3876 } else {
3877 // Call-back into JavaScript to convert the key to a string.
3878 bool has_pending_exception = false;
3879 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
3880 if (has_pending_exception) return Failure::Exception();
3881 key_string = Handle<String>::cast(converted);
3882 }
3883
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003884 key_string->TryFlatten();
ager@chromium.orge2902be2009-06-08 12:21:35 +00003885 return js_object->DeleteProperty(*key_string, JSObject::FORCE_DELETION);
3886}
3887
3888
lrn@chromium.org303ada72010-10-27 09:33:13 +00003889static MaybeObject* Runtime_SetProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003890 NoHandleAllocation ha;
3891 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
3892
3893 Handle<Object> object = args.at<Object>(0);
3894 Handle<Object> key = args.at<Object>(1);
3895 Handle<Object> value = args.at<Object>(2);
3896
3897 // Compute attributes.
3898 PropertyAttributes attributes = NONE;
3899 if (args.length() == 4) {
3900 CONVERT_CHECKED(Smi, value_obj, args[3]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003901 int unchecked_value = value_obj->value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003902 // Only attribute bits should be set.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003903 RUNTIME_ASSERT(
3904 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3905 attributes = static_cast<PropertyAttributes>(unchecked_value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003906 }
3907 return Runtime::SetObjectProperty(object, key, value, attributes);
3908}
3909
3910
3911// Set a local property, even if it is READ_ONLY. If the property does not
3912// exist, it will be added with attributes NONE.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003913static MaybeObject* Runtime_IgnoreAttributesAndSetProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003914 NoHandleAllocation ha;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003915 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003916 CONVERT_CHECKED(JSObject, object, args[0]);
3917 CONVERT_CHECKED(String, name, args[1]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003918 // Compute attributes.
3919 PropertyAttributes attributes = NONE;
3920 if (args.length() == 4) {
3921 CONVERT_CHECKED(Smi, value_obj, args[3]);
3922 int unchecked_value = value_obj->value();
3923 // Only attribute bits should be set.
3924 RUNTIME_ASSERT(
3925 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3926 attributes = static_cast<PropertyAttributes>(unchecked_value);
3927 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003928
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003929 return object->
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003930 SetLocalPropertyIgnoreAttributes(name, args[2], attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003931}
3932
3933
lrn@chromium.org303ada72010-10-27 09:33:13 +00003934static MaybeObject* Runtime_DeleteProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003935 NoHandleAllocation ha;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003936 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003937
3938 CONVERT_CHECKED(JSObject, object, args[0]);
3939 CONVERT_CHECKED(String, key, args[1]);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003940 CONVERT_SMI_CHECKED(strict, args[2]);
3941 return object->DeleteProperty(key, strict == kStrictMode
3942 ? JSObject::STRICT_DELETION
3943 : JSObject::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003944}
3945
3946
ager@chromium.org9085a012009-05-11 19:22:57 +00003947static Object* HasLocalPropertyImplementation(Handle<JSObject> object,
3948 Handle<String> key) {
3949 if (object->HasLocalProperty(*key)) return Heap::true_value();
3950 // Handle hidden prototypes. If there's a hidden prototype above this thing
3951 // then we have to check it for properties, because they are supposed to
3952 // look like they are on this object.
3953 Handle<Object> proto(object->GetPrototype());
3954 if (proto->IsJSObject() &&
3955 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
3956 return HasLocalPropertyImplementation(Handle<JSObject>::cast(proto), key);
3957 }
3958 return Heap::false_value();
3959}
3960
3961
lrn@chromium.org303ada72010-10-27 09:33:13 +00003962static MaybeObject* Runtime_HasLocalProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003963 NoHandleAllocation ha;
3964 ASSERT(args.length() == 2);
3965 CONVERT_CHECKED(String, key, args[1]);
3966
ager@chromium.org9085a012009-05-11 19:22:57 +00003967 Object* obj = args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003968 // Only JS objects can have properties.
ager@chromium.org9085a012009-05-11 19:22:57 +00003969 if (obj->IsJSObject()) {
3970 JSObject* object = JSObject::cast(obj);
3971 // Fast case - no interceptors.
3972 if (object->HasRealNamedProperty(key)) return Heap::true_value();
3973 // Slow case. Either it's not there or we have an interceptor. We should
3974 // have handles for this kind of deal.
3975 HandleScope scope;
3976 return HasLocalPropertyImplementation(Handle<JSObject>(object),
3977 Handle<String>(key));
3978 } else if (obj->IsString()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003979 // Well, there is one exception: Handle [] on strings.
3980 uint32_t index;
3981 if (key->AsArrayIndex(&index)) {
ager@chromium.org9085a012009-05-11 19:22:57 +00003982 String* string = String::cast(obj);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003983 if (index < static_cast<uint32_t>(string->length()))
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003984 return Heap::true_value();
3985 }
3986 }
3987 return Heap::false_value();
3988}
3989
3990
lrn@chromium.org303ada72010-10-27 09:33:13 +00003991static MaybeObject* Runtime_HasProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003992 NoHandleAllocation na;
3993 ASSERT(args.length() == 2);
3994
3995 // Only JS objects can have properties.
3996 if (args[0]->IsJSObject()) {
3997 JSObject* object = JSObject::cast(args[0]);
3998 CONVERT_CHECKED(String, key, args[1]);
3999 if (object->HasProperty(key)) return Heap::true_value();
4000 }
4001 return Heap::false_value();
4002}
4003
4004
lrn@chromium.org303ada72010-10-27 09:33:13 +00004005static MaybeObject* Runtime_HasElement(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004006 NoHandleAllocation na;
4007 ASSERT(args.length() == 2);
4008
4009 // Only JS objects can have elements.
4010 if (args[0]->IsJSObject()) {
4011 JSObject* object = JSObject::cast(args[0]);
4012 CONVERT_CHECKED(Smi, index_obj, args[1]);
4013 uint32_t index = index_obj->value();
4014 if (object->HasElement(index)) return Heap::true_value();
4015 }
4016 return Heap::false_value();
4017}
4018
4019
lrn@chromium.org303ada72010-10-27 09:33:13 +00004020static MaybeObject* Runtime_IsPropertyEnumerable(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004021 NoHandleAllocation ha;
4022 ASSERT(args.length() == 2);
4023
4024 CONVERT_CHECKED(JSObject, object, args[0]);
4025 CONVERT_CHECKED(String, key, args[1]);
4026
4027 uint32_t index;
4028 if (key->AsArrayIndex(&index)) {
4029 return Heap::ToBoolean(object->HasElement(index));
4030 }
4031
ager@chromium.org870a0b62008-11-04 11:43:05 +00004032 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
4033 return Heap::ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004034}
4035
4036
lrn@chromium.org303ada72010-10-27 09:33:13 +00004037static MaybeObject* Runtime_GetPropertyNames(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004038 HandleScope scope;
4039 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00004040 CONVERT_ARG_CHECKED(JSObject, object, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004041 return *GetKeysFor(object);
4042}
4043
4044
4045// Returns either a FixedArray as Runtime_GetPropertyNames,
4046// or, if the given object has an enum cache that contains
4047// all enumerable properties of the object and its prototypes
4048// have none, the map of the object. This is used to speed up
4049// the check for deletions during a for-in.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004050static MaybeObject* Runtime_GetPropertyNamesFast(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004051 ASSERT(args.length() == 1);
4052
4053 CONVERT_CHECKED(JSObject, raw_object, args[0]);
4054
4055 if (raw_object->IsSimpleEnum()) return raw_object->map();
4056
4057 HandleScope scope;
4058 Handle<JSObject> object(raw_object);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004059 Handle<FixedArray> content = GetKeysInFixedArrayFor(object,
4060 INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004061
4062 // Test again, since cache may have been built by preceding call.
4063 if (object->IsSimpleEnum()) return object->map();
4064
4065 return *content;
4066}
4067
4068
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004069// Find the length of the prototype chain that is to to handled as one. If a
4070// prototype object is hidden it is to be viewed as part of the the object it
4071// is prototype for.
4072static int LocalPrototypeChainLength(JSObject* obj) {
4073 int count = 1;
4074 Object* proto = obj->GetPrototype();
4075 while (proto->IsJSObject() &&
4076 JSObject::cast(proto)->map()->is_hidden_prototype()) {
4077 count++;
4078 proto = JSObject::cast(proto)->GetPrototype();
4079 }
4080 return count;
4081}
4082
4083
4084// Return the names of the local named properties.
4085// args[0]: object
lrn@chromium.org303ada72010-10-27 09:33:13 +00004086static MaybeObject* Runtime_GetLocalPropertyNames(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004087 HandleScope scope;
4088 ASSERT(args.length() == 1);
4089 if (!args[0]->IsJSObject()) {
4090 return Heap::undefined_value();
4091 }
4092 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4093
4094 // Skip the global proxy as it has no properties and always delegates to the
4095 // real global object.
4096 if (obj->IsJSGlobalProxy()) {
4097 // Only collect names if access is permitted.
4098 if (obj->IsAccessCheckNeeded() &&
4099 !Top::MayNamedAccess(*obj, Heap::undefined_value(), v8::ACCESS_KEYS)) {
4100 Top::ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
4101 return *Factory::NewJSArray(0);
4102 }
4103 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
4104 }
4105
4106 // Find the number of objects making up this.
4107 int length = LocalPrototypeChainLength(*obj);
4108
4109 // Find the number of local properties for each of the objects.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00004110 ScopedVector<int> local_property_count(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004111 int total_property_count = 0;
4112 Handle<JSObject> jsproto = obj;
4113 for (int i = 0; i < length; i++) {
4114 // Only collect names if access is permitted.
4115 if (jsproto->IsAccessCheckNeeded() &&
4116 !Top::MayNamedAccess(*jsproto,
4117 Heap::undefined_value(),
4118 v8::ACCESS_KEYS)) {
4119 Top::ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
4120 return *Factory::NewJSArray(0);
4121 }
4122 int n;
4123 n = jsproto->NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE));
4124 local_property_count[i] = n;
4125 total_property_count += n;
4126 if (i < length - 1) {
4127 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4128 }
4129 }
4130
4131 // Allocate an array with storage for all the property names.
4132 Handle<FixedArray> names = Factory::NewFixedArray(total_property_count);
4133
4134 // Get the property names.
4135 jsproto = obj;
4136 int proto_with_hidden_properties = 0;
4137 for (int i = 0; i < length; i++) {
4138 jsproto->GetLocalPropertyNames(*names,
4139 i == 0 ? 0 : local_property_count[i - 1]);
4140 if (!GetHiddenProperties(jsproto, false)->IsUndefined()) {
4141 proto_with_hidden_properties++;
4142 }
4143 if (i < length - 1) {
4144 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4145 }
4146 }
4147
4148 // Filter out name of hidden propeties object.
4149 if (proto_with_hidden_properties > 0) {
4150 Handle<FixedArray> old_names = names;
4151 names = Factory::NewFixedArray(
4152 names->length() - proto_with_hidden_properties);
4153 int dest_pos = 0;
4154 for (int i = 0; i < total_property_count; i++) {
4155 Object* name = old_names->get(i);
4156 if (name == Heap::hidden_symbol()) {
4157 continue;
4158 }
4159 names->set(dest_pos++, name);
4160 }
4161 }
4162
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004163 return *Factory::NewJSArrayWithElements(names);
4164}
4165
4166
4167// Return the names of the local indexed properties.
4168// args[0]: object
lrn@chromium.org303ada72010-10-27 09:33:13 +00004169static MaybeObject* Runtime_GetLocalElementNames(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004170 HandleScope scope;
4171 ASSERT(args.length() == 1);
4172 if (!args[0]->IsJSObject()) {
4173 return Heap::undefined_value();
4174 }
4175 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4176
4177 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
4178 Handle<FixedArray> names = Factory::NewFixedArray(n);
4179 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
4180 return *Factory::NewJSArrayWithElements(names);
4181}
4182
4183
4184// Return information on whether an object has a named or indexed interceptor.
4185// args[0]: object
lrn@chromium.org303ada72010-10-27 09:33:13 +00004186static MaybeObject* Runtime_GetInterceptorInfo(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004187 HandleScope scope;
4188 ASSERT(args.length() == 1);
4189 if (!args[0]->IsJSObject()) {
4190 return Smi::FromInt(0);
4191 }
4192 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4193
4194 int result = 0;
4195 if (obj->HasNamedInterceptor()) result |= 2;
4196 if (obj->HasIndexedInterceptor()) result |= 1;
4197
4198 return Smi::FromInt(result);
4199}
4200
4201
4202// Return property names from named interceptor.
4203// args[0]: object
lrn@chromium.org303ada72010-10-27 09:33:13 +00004204static MaybeObject* Runtime_GetNamedInterceptorPropertyNames(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004205 HandleScope scope;
4206 ASSERT(args.length() == 1);
4207 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4208
4209 if (obj->HasNamedInterceptor()) {
4210 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
4211 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4212 }
4213 return Heap::undefined_value();
4214}
4215
4216
4217// Return element names from indexed interceptor.
4218// args[0]: object
lrn@chromium.org303ada72010-10-27 09:33:13 +00004219static MaybeObject* Runtime_GetIndexedInterceptorElementNames(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004220 HandleScope scope;
4221 ASSERT(args.length() == 1);
4222 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4223
4224 if (obj->HasIndexedInterceptor()) {
4225 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
4226 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4227 }
4228 return Heap::undefined_value();
4229}
4230
4231
lrn@chromium.org303ada72010-10-27 09:33:13 +00004232static MaybeObject* Runtime_LocalKeys(Arguments args) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004233 ASSERT_EQ(args.length(), 1);
4234 CONVERT_CHECKED(JSObject, raw_object, args[0]);
4235 HandleScope scope;
4236 Handle<JSObject> object(raw_object);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004237
4238 if (object->IsJSGlobalProxy()) {
ricow@chromium.org65001782011-02-15 13:36:41 +00004239 // Do access checks before going to the global object.
4240 if (object->IsAccessCheckNeeded() &&
4241 !Top::MayNamedAccess(*object, Heap::undefined_value(),
4242 v8::ACCESS_KEYS)) {
4243 Top::ReportFailedAccessCheck(*object, v8::ACCESS_KEYS);
4244 return *Factory::NewJSArray(0);
4245 }
4246
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004247 Handle<Object> proto(object->GetPrototype());
4248 // If proxy is detached we simply return an empty array.
4249 if (proto->IsNull()) return *Factory::NewJSArray(0);
4250 object = Handle<JSObject>::cast(proto);
4251 }
4252
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004253 Handle<FixedArray> contents = GetKeysInFixedArrayFor(object,
4254 LOCAL_ONLY);
4255 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
4256 // property array and since the result is mutable we have to create
4257 // a fresh clone on each invocation.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004258 int length = contents->length();
4259 Handle<FixedArray> copy = Factory::NewFixedArray(length);
4260 for (int i = 0; i < length; i++) {
4261 Object* entry = contents->get(i);
4262 if (entry->IsString()) {
4263 copy->set(i, entry);
4264 } else {
4265 ASSERT(entry->IsNumber());
4266 HandleScope scope;
4267 Handle<Object> entry_handle(entry);
4268 Handle<Object> entry_str = Factory::NumberToString(entry_handle);
4269 copy->set(i, *entry_str);
4270 }
4271 }
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004272 return *Factory::NewJSArrayWithElements(copy);
4273}
4274
4275
lrn@chromium.org303ada72010-10-27 09:33:13 +00004276static MaybeObject* Runtime_GetArgumentsProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004277 NoHandleAllocation ha;
4278 ASSERT(args.length() == 1);
4279
4280 // Compute the frame holding the arguments.
4281 JavaScriptFrameIterator it;
4282 it.AdvanceToArgumentsFrame();
4283 JavaScriptFrame* frame = it.frame();
4284
4285 // Get the actual number of provided arguments.
4286 const uint32_t n = frame->GetProvidedParametersCount();
4287
4288 // Try to convert the key to an index. If successful and within
4289 // index return the the argument from the frame.
4290 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004291 if (args[0]->ToArrayIndex(&index) && index < n) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004292 return frame->GetParameter(index);
4293 }
4294
4295 // Convert the key to a string.
4296 HandleScope scope;
4297 bool exception = false;
4298 Handle<Object> converted =
4299 Execution::ToString(args.at<Object>(0), &exception);
4300 if (exception) return Failure::Exception();
4301 Handle<String> key = Handle<String>::cast(converted);
4302
4303 // Try to convert the string key into an array index.
4304 if (key->AsArrayIndex(&index)) {
4305 if (index < n) {
4306 return frame->GetParameter(index);
4307 } else {
4308 return Top::initial_object_prototype()->GetElement(index);
4309 }
4310 }
4311
4312 // Handle special arguments properties.
4313 if (key->Equals(Heap::length_symbol())) return Smi::FromInt(n);
4314 if (key->Equals(Heap::callee_symbol())) return frame->function();
4315
4316 // Lookup in the initial Object.prototype object.
4317 return Top::initial_object_prototype()->GetProperty(*key);
4318}
4319
4320
lrn@chromium.org303ada72010-10-27 09:33:13 +00004321static MaybeObject* Runtime_ToFastProperties(Arguments args) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004322 HandleScope scope;
4323
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004324 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004325 Handle<Object> object = args.at<Object>(0);
4326 if (object->IsJSObject()) {
4327 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
ager@chromium.org5c838252010-02-19 08:53:10 +00004328 if (!js_object->HasFastProperties() && !js_object->IsGlobalObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004329 MaybeObject* ok = js_object->TransformToFastProperties(0);
4330 if (ok->IsRetryAfterGC()) return ok;
ager@chromium.org5c838252010-02-19 08:53:10 +00004331 }
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004332 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004333 return *object;
4334}
4335
4336
lrn@chromium.org303ada72010-10-27 09:33:13 +00004337static MaybeObject* Runtime_ToSlowProperties(Arguments args) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004338 HandleScope scope;
4339
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004340 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004341 Handle<Object> object = args.at<Object>(0);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004342 if (object->IsJSObject() && !object->IsJSGlobalProxy()) {
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004343 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004344 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004345 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004346 return *object;
4347}
4348
4349
lrn@chromium.org303ada72010-10-27 09:33:13 +00004350static MaybeObject* Runtime_ToBool(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004351 NoHandleAllocation ha;
4352 ASSERT(args.length() == 1);
4353
4354 return args[0]->ToBoolean();
4355}
4356
4357
4358// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
4359// Possible optimizations: put the type string into the oddballs.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004360static MaybeObject* Runtime_Typeof(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004361 NoHandleAllocation ha;
4362
4363 Object* obj = args[0];
4364 if (obj->IsNumber()) return Heap::number_symbol();
4365 HeapObject* heap_obj = HeapObject::cast(obj);
4366
4367 // typeof an undetectable object is 'undefined'
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004368 if (heap_obj->map()->is_undetectable()) return Heap::undefined_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004369
4370 InstanceType instance_type = heap_obj->map()->instance_type();
4371 if (instance_type < FIRST_NONSTRING_TYPE) {
4372 return Heap::string_symbol();
4373 }
4374
4375 switch (instance_type) {
4376 case ODDBALL_TYPE:
4377 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
4378 return Heap::boolean_symbol();
4379 }
4380 if (heap_obj->IsNull()) {
4381 return Heap::object_symbol();
4382 }
4383 ASSERT(heap_obj->IsUndefined());
4384 return Heap::undefined_symbol();
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00004385 case JS_FUNCTION_TYPE: case JS_REGEXP_TYPE:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004386 return Heap::function_symbol();
4387 default:
4388 // For any kind of object not handled above, the spec rule for
4389 // host objects gives that it is okay to return "object"
4390 return Heap::object_symbol();
4391 }
4392}
4393
4394
lrn@chromium.org25156de2010-04-06 13:10:27 +00004395static bool AreDigits(const char*s, int from, int to) {
4396 for (int i = from; i < to; i++) {
4397 if (s[i] < '0' || s[i] > '9') return false;
4398 }
4399
4400 return true;
4401}
4402
4403
4404static int ParseDecimalInteger(const char*s, int from, int to) {
4405 ASSERT(to - from < 10); // Overflow is not possible.
4406 ASSERT(from < to);
4407 int d = s[from] - '0';
4408
4409 for (int i = from + 1; i < to; i++) {
4410 d = 10 * d + (s[i] - '0');
4411 }
4412
4413 return d;
4414}
4415
4416
lrn@chromium.org303ada72010-10-27 09:33:13 +00004417static MaybeObject* Runtime_StringToNumber(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004418 NoHandleAllocation ha;
4419 ASSERT(args.length() == 1);
4420 CONVERT_CHECKED(String, subject, args[0]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004421 subject->TryFlatten();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004422
4423 // Fast case: short integer or some sorts of junk values.
4424 int len = subject->length();
4425 if (subject->IsSeqAsciiString()) {
4426 if (len == 0) return Smi::FromInt(0);
4427
4428 char const* data = SeqAsciiString::cast(subject)->GetChars();
4429 bool minus = (data[0] == '-');
4430 int start_pos = (minus ? 1 : 0);
4431
4432 if (start_pos == len) {
4433 return Heap::nan_value();
4434 } else if (data[start_pos] > '9') {
4435 // Fast check for a junk value. A valid string may start from a
4436 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
4437 // the 'I' character ('Infinity'). All of that have codes not greater than
4438 // '9' except 'I'.
4439 if (data[start_pos] != 'I') {
4440 return Heap::nan_value();
4441 }
4442 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
4443 // The maximal/minimal smi has 10 digits. If the string has less digits we
4444 // know it will fit into the smi-data type.
4445 int d = ParseDecimalInteger(data, start_pos, len);
4446 if (minus) {
4447 if (d == 0) return Heap::minus_zero_value();
4448 d = -d;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004449 } else if (!subject->HasHashCode() &&
4450 len <= String::kMaxArrayIndexSize &&
4451 (len == 1 || data[0] != '0')) {
4452 // String hash is not calculated yet but all the data are present.
4453 // Update the hash field to speed up sequential convertions.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00004454 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004455#ifdef DEBUG
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004456 subject->Hash(); // Force hash calculation.
4457 ASSERT_EQ(static_cast<int>(subject->hash_field()),
4458 static_cast<int>(hash));
4459#endif
4460 subject->set_hash_field(hash);
lrn@chromium.org25156de2010-04-06 13:10:27 +00004461 }
4462 return Smi::FromInt(d);
4463 }
4464 }
4465
4466 // Slower case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004467 return Heap::NumberFromDouble(StringToDouble(subject, ALLOW_HEX));
4468}
4469
4470
lrn@chromium.org303ada72010-10-27 09:33:13 +00004471static MaybeObject* Runtime_StringFromCharCodeArray(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004472 NoHandleAllocation ha;
4473 ASSERT(args.length() == 1);
4474
4475 CONVERT_CHECKED(JSArray, codes, args[0]);
4476 int length = Smi::cast(codes->length())->value();
4477
4478 // Check if the string can be ASCII.
4479 int i;
4480 for (i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004481 Object* element;
4482 { MaybeObject* maybe_element = codes->GetElement(i);
4483 // We probably can't get an exception here, but just in order to enforce
4484 // the checking of inputs in the runtime calls we check here.
4485 if (!maybe_element->ToObject(&element)) return maybe_element;
4486 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004487 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
4488 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
4489 break;
4490 }
4491
lrn@chromium.org303ada72010-10-27 09:33:13 +00004492 MaybeObject* maybe_object = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004493 if (i == length) { // The string is ASCII.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004494 maybe_object = Heap::AllocateRawAsciiString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004495 } else { // The string is not ASCII.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004496 maybe_object = Heap::AllocateRawTwoByteString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004497 }
4498
lrn@chromium.org303ada72010-10-27 09:33:13 +00004499 Object* object = NULL;
4500 if (!maybe_object->ToObject(&object)) return maybe_object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004501 String* result = String::cast(object);
4502 for (int i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004503 Object* element;
4504 { MaybeObject* maybe_element = codes->GetElement(i);
4505 if (!maybe_element->ToObject(&element)) return maybe_element;
4506 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004507 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004508 result->Set(i, chr & 0xffff);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004509 }
4510 return result;
4511}
4512
4513
4514// kNotEscaped is generated by the following:
4515//
4516// #!/bin/perl
4517// for (my $i = 0; $i < 256; $i++) {
4518// print "\n" if $i % 16 == 0;
4519// my $c = chr($i);
4520// my $escaped = 1;
4521// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
4522// print $escaped ? "0, " : "1, ";
4523// }
4524
4525
4526static bool IsNotEscaped(uint16_t character) {
4527 // Only for 8 bit characters, the rest are always escaped (in a different way)
4528 ASSERT(character < 256);
4529 static const char kNotEscaped[256] = {
4530 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4531 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4532 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
4533 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
4534 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4535 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
4536 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4537 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
4538 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4539 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4540 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4541 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4542 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4543 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4544 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4545 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4546 };
4547 return kNotEscaped[character] != 0;
4548}
4549
4550
lrn@chromium.org303ada72010-10-27 09:33:13 +00004551static MaybeObject* Runtime_URIEscape(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004552 const char hex_chars[] = "0123456789ABCDEF";
4553 NoHandleAllocation ha;
4554 ASSERT(args.length() == 1);
4555 CONVERT_CHECKED(String, source, args[0]);
4556
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004557 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004558
4559 int escaped_length = 0;
4560 int length = source->length();
4561 {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004562 Access<StringInputBuffer> buffer(&runtime_string_input_buffer);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004563 buffer->Reset(source);
4564 while (buffer->has_more()) {
4565 uint16_t character = buffer->GetNext();
4566 if (character >= 256) {
4567 escaped_length += 6;
4568 } else if (IsNotEscaped(character)) {
4569 escaped_length++;
4570 } else {
4571 escaped_length += 3;
4572 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004573 // We don't allow strings that are longer than a maximal length.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004574 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004575 if (escaped_length > String::kMaxLength) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004576 Top::context()->mark_out_of_memory();
4577 return Failure::OutOfMemoryException();
4578 }
4579 }
4580 }
4581 // No length change implies no change. Return original string if no change.
4582 if (escaped_length == length) {
4583 return source;
4584 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00004585 Object* o;
4586 { MaybeObject* maybe_o = Heap::AllocateRawAsciiString(escaped_length);
4587 if (!maybe_o->ToObject(&o)) return maybe_o;
4588 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004589 String* destination = String::cast(o);
4590 int dest_position = 0;
4591
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004592 Access<StringInputBuffer> buffer(&runtime_string_input_buffer);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004593 buffer->Rewind();
4594 while (buffer->has_more()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00004595 uint16_t chr = buffer->GetNext();
4596 if (chr >= 256) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004597 destination->Set(dest_position, '%');
4598 destination->Set(dest_position+1, 'u');
4599 destination->Set(dest_position+2, hex_chars[chr >> 12]);
4600 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]);
4601 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]);
4602 destination->Set(dest_position+5, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004603 dest_position += 6;
ager@chromium.org870a0b62008-11-04 11:43:05 +00004604 } else if (IsNotEscaped(chr)) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004605 destination->Set(dest_position, chr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004606 dest_position++;
4607 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004608 destination->Set(dest_position, '%');
4609 destination->Set(dest_position+1, hex_chars[chr >> 4]);
4610 destination->Set(dest_position+2, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004611 dest_position += 3;
4612 }
4613 }
4614 return destination;
4615}
4616
4617
4618static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
4619 static const signed char kHexValue['g'] = {
4620 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4621 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4622 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4623 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
4624 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4625 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4626 -1, 10, 11, 12, 13, 14, 15 };
4627
4628 if (character1 > 'f') return -1;
4629 int hi = kHexValue[character1];
4630 if (hi == -1) return -1;
4631 if (character2 > 'f') return -1;
4632 int lo = kHexValue[character2];
4633 if (lo == -1) return -1;
4634 return (hi << 4) + lo;
4635}
4636
4637
ager@chromium.org870a0b62008-11-04 11:43:05 +00004638static inline int Unescape(String* source,
ager@chromium.org870a0b62008-11-04 11:43:05 +00004639 int i,
4640 int length,
4641 int* step) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004642 uint16_t character = source->Get(i);
ager@chromium.org870a0b62008-11-04 11:43:05 +00004643 int32_t hi = 0;
4644 int32_t lo = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004645 if (character == '%' &&
4646 i <= length - 6 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004647 source->Get(i + 1) == 'u' &&
4648 (hi = TwoDigitHex(source->Get(i + 2),
4649 source->Get(i + 3))) != -1 &&
4650 (lo = TwoDigitHex(source->Get(i + 4),
4651 source->Get(i + 5))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004652 *step = 6;
4653 return (hi << 8) + lo;
4654 } else if (character == '%' &&
4655 i <= length - 3 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004656 (lo = TwoDigitHex(source->Get(i + 1),
4657 source->Get(i + 2))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004658 *step = 3;
4659 return lo;
4660 } else {
4661 *step = 1;
4662 return character;
4663 }
4664}
4665
4666
lrn@chromium.org303ada72010-10-27 09:33:13 +00004667static MaybeObject* Runtime_URIUnescape(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004668 NoHandleAllocation ha;
4669 ASSERT(args.length() == 1);
4670 CONVERT_CHECKED(String, source, args[0]);
4671
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004672 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004673
4674 bool ascii = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004675 int length = source->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004676
4677 int unescaped_length = 0;
4678 for (int i = 0; i < length; unescaped_length++) {
4679 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004680 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004681 ascii = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004682 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004683 i += step;
4684 }
4685
4686 // No length change implies no change. Return original string if no change.
4687 if (unescaped_length == length)
4688 return source;
4689
lrn@chromium.org303ada72010-10-27 09:33:13 +00004690 Object* o;
4691 { MaybeObject* maybe_o = ascii ?
4692 Heap::AllocateRawAsciiString(unescaped_length) :
4693 Heap::AllocateRawTwoByteString(unescaped_length);
4694 if (!maybe_o->ToObject(&o)) return maybe_o;
4695 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004696 String* destination = String::cast(o);
4697
4698 int dest_position = 0;
4699 for (int i = 0; i < length; dest_position++) {
4700 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004701 destination->Set(dest_position, Unescape(source, i, length, &step));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004702 i += step;
4703 }
4704 return destination;
4705}
4706
4707
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004708static const unsigned int kQuoteTableLength = 128u;
4709
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004710static const int kJsonQuotesCharactersPerEntry = 8;
4711static const char* const JsonQuotes =
4712 "\\u0000 \\u0001 \\u0002 \\u0003 "
4713 "\\u0004 \\u0005 \\u0006 \\u0007 "
4714 "\\b \\t \\n \\u000b "
4715 "\\f \\r \\u000e \\u000f "
4716 "\\u0010 \\u0011 \\u0012 \\u0013 "
4717 "\\u0014 \\u0015 \\u0016 \\u0017 "
4718 "\\u0018 \\u0019 \\u001a \\u001b "
4719 "\\u001c \\u001d \\u001e \\u001f "
4720 " ! \\\" # "
4721 "$ % & ' "
4722 "( ) * + "
4723 ", - . / "
4724 "0 1 2 3 "
4725 "4 5 6 7 "
4726 "8 9 : ; "
4727 "< = > ? "
4728 "@ A B C "
4729 "D E F G "
4730 "H I J K "
4731 "L M N O "
4732 "P Q R S "
4733 "T U V W "
4734 "X Y Z [ "
4735 "\\\\ ] ^ _ "
4736 "` a b c "
4737 "d e f g "
4738 "h i j k "
4739 "l m n o "
4740 "p q r s "
4741 "t u v w "
4742 "x y z { "
4743 "| } ~ \177 ";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004744
4745
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004746// For a string that is less than 32k characters it should always be
4747// possible to allocate it in new space.
4748static const int kMaxGuaranteedNewSpaceString = 32 * 1024;
4749
4750
4751// Doing JSON quoting cannot make the string more than this many times larger.
4752static const int kJsonQuoteWorstCaseBlowup = 6;
4753
4754
4755// Covers the entire ASCII range (all other characters are unchanged by JSON
4756// quoting).
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004757static const byte JsonQuoteLengths[kQuoteTableLength] = {
4758 6, 6, 6, 6, 6, 6, 6, 6,
4759 2, 2, 2, 6, 2, 2, 6, 6,
4760 6, 6, 6, 6, 6, 6, 6, 6,
4761 6, 6, 6, 6, 6, 6, 6, 6,
4762 1, 1, 2, 1, 1, 1, 1, 1,
4763 1, 1, 1, 1, 1, 1, 1, 1,
4764 1, 1, 1, 1, 1, 1, 1, 1,
4765 1, 1, 1, 1, 1, 1, 1, 1,
4766 1, 1, 1, 1, 1, 1, 1, 1,
4767 1, 1, 1, 1, 1, 1, 1, 1,
4768 1, 1, 1, 1, 1, 1, 1, 1,
4769 1, 1, 1, 1, 2, 1, 1, 1,
4770 1, 1, 1, 1, 1, 1, 1, 1,
4771 1, 1, 1, 1, 1, 1, 1, 1,
4772 1, 1, 1, 1, 1, 1, 1, 1,
4773 1, 1, 1, 1, 1, 1, 1, 1,
4774};
4775
4776
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004777template <typename StringType>
4778MaybeObject* AllocateRawString(int length);
4779
4780
4781template <>
4782MaybeObject* AllocateRawString<SeqTwoByteString>(int length) {
4783 return Heap::AllocateRawTwoByteString(length);
4784}
4785
4786
4787template <>
4788MaybeObject* AllocateRawString<SeqAsciiString>(int length) {
4789 return Heap::AllocateRawAsciiString(length);
4790}
4791
4792
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004793template <typename Char, typename StringType, bool comma>
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004794static MaybeObject* SlowQuoteJsonString(Vector<const Char> characters) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004795 int length = characters.length();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004796 const Char* read_cursor = characters.start();
4797 const Char* end = read_cursor + length;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004798 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004799 int quoted_length = kSpaceForQuotes;
4800 while (read_cursor < end) {
4801 Char c = *(read_cursor++);
4802 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
4803 quoted_length++;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004804 } else {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004805 quoted_length += JsonQuoteLengths[static_cast<unsigned>(c)];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004806 }
4807 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004808 MaybeObject* new_alloc = AllocateRawString<StringType>(quoted_length);
4809 Object* new_object;
4810 if (!new_alloc->ToObject(&new_object)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004811 return new_alloc;
4812 }
4813 StringType* new_string = StringType::cast(new_object);
4814
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004815 Char* write_cursor = reinterpret_cast<Char*>(
4816 new_string->address() + SeqAsciiString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004817 if (comma) *(write_cursor++) = ',';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004818 *(write_cursor++) = '"';
4819
4820 read_cursor = characters.start();
4821 while (read_cursor < end) {
4822 Char c = *(read_cursor++);
4823 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
4824 *(write_cursor++) = c;
4825 } else {
4826 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
4827 const char* replacement = JsonQuotes +
4828 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
4829 for (int i = 0; i < len; i++) {
4830 *write_cursor++ = *replacement++;
4831 }
4832 }
4833 }
4834 *(write_cursor++) = '"';
4835 return new_string;
4836}
4837
4838
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004839template <typename Char, typename StringType, bool comma>
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004840static MaybeObject* QuoteJsonString(Vector<const Char> characters) {
4841 int length = characters.length();
4842 Counters::quote_json_char_count.Increment(length);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004843 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004844 int worst_case_length = length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotes;
4845 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004846 return SlowQuoteJsonString<Char, StringType, comma>(characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004847 }
4848
4849 MaybeObject* new_alloc = AllocateRawString<StringType>(worst_case_length);
4850 Object* new_object;
4851 if (!new_alloc->ToObject(&new_object)) {
4852 return new_alloc;
4853 }
4854 if (!Heap::new_space()->Contains(new_object)) {
4855 // Even if our string is small enough to fit in new space we still have to
4856 // handle it being allocated in old space as may happen in the third
4857 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
4858 // CEntryStub::GenerateCore.
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004859 return SlowQuoteJsonString<Char, StringType, comma>(characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004860 }
4861 StringType* new_string = StringType::cast(new_object);
4862 ASSERT(Heap::new_space()->Contains(new_string));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004863
4864 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize);
4865 Char* write_cursor = reinterpret_cast<Char*>(
4866 new_string->address() + SeqAsciiString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004867 if (comma) *(write_cursor++) = ',';
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004868 *(write_cursor++) = '"';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004869
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004870 const Char* read_cursor = characters.start();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004871 const Char* end = read_cursor + length;
4872 while (read_cursor < end) {
4873 Char c = *(read_cursor++);
4874 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
4875 *(write_cursor++) = c;
4876 } else {
4877 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
4878 const char* replacement = JsonQuotes +
4879 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
4880 write_cursor[0] = replacement[0];
4881 if (len > 1) {
4882 write_cursor[1] = replacement[1];
4883 if (len > 2) {
4884 ASSERT(len == 6);
4885 write_cursor[2] = replacement[2];
4886 write_cursor[3] = replacement[3];
4887 write_cursor[4] = replacement[4];
4888 write_cursor[5] = replacement[5];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004889 }
4890 }
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004891 write_cursor += len;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004892 }
4893 }
4894 *(write_cursor++) = '"';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004895
4896 int final_length = static_cast<int>(
4897 write_cursor - reinterpret_cast<Char*>(
4898 new_string->address() + SeqAsciiString::kHeaderSize));
4899 Heap::new_space()->ShrinkStringAtAllocationBoundary<StringType>(new_string,
4900 final_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004901 return new_string;
4902}
4903
4904
4905static MaybeObject* Runtime_QuoteJSONString(Arguments args) {
4906 NoHandleAllocation ha;
4907 CONVERT_CHECKED(String, str, args[0]);
4908 if (!str->IsFlat()) {
4909 MaybeObject* try_flatten = str->TryFlatten();
4910 Object* flat;
4911 if (!try_flatten->ToObject(&flat)) {
4912 return try_flatten;
4913 }
4914 str = String::cast(flat);
4915 ASSERT(str->IsFlat());
4916 }
4917 if (str->IsTwoByteRepresentation()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004918 return QuoteJsonString<uc16, SeqTwoByteString, false>(str->ToUC16Vector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004919 } else {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004920 return QuoteJsonString<char, SeqAsciiString, false>(str->ToAsciiVector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004921 }
4922}
4923
4924
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004925static MaybeObject* Runtime_QuoteJSONStringComma(Arguments args) {
4926 NoHandleAllocation ha;
4927 CONVERT_CHECKED(String, str, args[0]);
4928 if (!str->IsFlat()) {
4929 MaybeObject* try_flatten = str->TryFlatten();
4930 Object* flat;
4931 if (!try_flatten->ToObject(&flat)) {
4932 return try_flatten;
4933 }
4934 str = String::cast(flat);
4935 ASSERT(str->IsFlat());
4936 }
4937 if (str->IsTwoByteRepresentation()) {
4938 return QuoteJsonString<uc16, SeqTwoByteString, true>(str->ToUC16Vector());
4939 } else {
4940 return QuoteJsonString<char, SeqAsciiString, true>(str->ToAsciiVector());
4941 }
4942}
4943
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004944
lrn@chromium.org303ada72010-10-27 09:33:13 +00004945static MaybeObject* Runtime_StringParseInt(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004946 NoHandleAllocation ha;
4947
4948 CONVERT_CHECKED(String, s, args[0]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00004949 CONVERT_SMI_CHECKED(radix, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004950
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004951 s->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004952
lrn@chromium.org25156de2010-04-06 13:10:27 +00004953 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
4954 double value = StringToInt(s, radix);
4955 return Heap::NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004956}
4957
4958
lrn@chromium.org303ada72010-10-27 09:33:13 +00004959static MaybeObject* Runtime_StringParseFloat(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004960 NoHandleAllocation ha;
4961 CONVERT_CHECKED(String, str, args[0]);
4962
4963 // ECMA-262 section 15.1.2.3, empty string is NaN
4964 double value = StringToDouble(str, ALLOW_TRAILING_JUNK, OS::nan_value());
4965
4966 // Create a number object from the value.
4967 return Heap::NumberFromDouble(value);
4968}
4969
4970
4971static unibrow::Mapping<unibrow::ToUppercase, 128> to_upper_mapping;
4972static unibrow::Mapping<unibrow::ToLowercase, 128> to_lower_mapping;
4973
4974
4975template <class Converter>
lrn@chromium.org303ada72010-10-27 09:33:13 +00004976MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
4977 String* s,
4978 int length,
4979 int input_string_length,
4980 unibrow::Mapping<Converter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004981 // We try this twice, once with the assumption that the result is no longer
4982 // than the input and, if that assumption breaks, again with the exact
4983 // length. This may not be pretty, but it is nicer than what was here before
4984 // and I hereby claim my vaffel-is.
4985 //
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004986 // Allocate the resulting string.
4987 //
4988 // NOTE: This assumes that the upper/lower case of an ascii
4989 // character is also ascii. This is currently the case, but it
4990 // might break in the future if we implement more context and locale
4991 // dependent upper/lower conversions.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004992 Object* o;
4993 { MaybeObject* maybe_o = s->IsAsciiRepresentation()
4994 ? Heap::AllocateRawAsciiString(length)
4995 : Heap::AllocateRawTwoByteString(length);
4996 if (!maybe_o->ToObject(&o)) return maybe_o;
4997 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004998 String* result = String::cast(o);
4999 bool has_changed_character = false;
5000
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005001 // Convert all characters to upper case, assuming that they will fit
5002 // in the buffer
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00005003 Access<StringInputBuffer> buffer(&runtime_string_input_buffer);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005004 buffer->Reset(s);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005005 unibrow::uchar chars[Converter::kMaxWidth];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005006 // We can assume that the string is not empty
5007 uc32 current = buffer->GetNext();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005008 for (int i = 0; i < length;) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00005009 bool has_next = buffer->has_more();
5010 uc32 next = has_next ? buffer->GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005011 int char_length = mapping->get(current, next, chars);
5012 if (char_length == 0) {
5013 // The case conversion of this character is the character itself.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005014 result->Set(i, current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005015 i++;
5016 } else if (char_length == 1) {
5017 // Common case: converting the letter resulted in one character.
5018 ASSERT(static_cast<uc32>(chars[0]) != current);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005019 result->Set(i, chars[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005020 has_changed_character = true;
5021 i++;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005022 } else if (length == input_string_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005023 // We've assumed that the result would be as long as the
5024 // input but here is a character that converts to several
5025 // characters. No matter, we calculate the exact length
5026 // of the result and try the whole thing again.
5027 //
5028 // Note that this leaves room for optimization. We could just
5029 // memcpy what we already have to the result string. Also,
5030 // the result string is the last object allocated we could
5031 // "realloc" it and probably, in the vast majority of cases,
5032 // extend the existing string to be able to hold the full
5033 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00005034 int next_length = 0;
5035 if (has_next) {
5036 next_length = mapping->get(next, 0, chars);
5037 if (next_length == 0) next_length = 1;
5038 }
5039 int current_length = i + char_length + next_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005040 while (buffer->has_more()) {
5041 current = buffer->GetNext();
ager@chromium.org7c537e22008-10-16 08:43:32 +00005042 // NOTE: we use 0 as the next character here because, while
5043 // the next character may affect what a character converts to,
5044 // it does not in any case affect the length of what it convert
5045 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005046 int char_length = mapping->get(current, 0, chars);
5047 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00005048 current_length += char_length;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005049 if (current_length > Smi::kMaxValue) {
5050 Top::context()->mark_out_of_memory();
5051 return Failure::OutOfMemoryException();
5052 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005053 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005054 // Try again with the real length.
5055 return Smi::FromInt(current_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005056 } else {
5057 for (int j = 0; j < char_length; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005058 result->Set(i, chars[j]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005059 i++;
5060 }
5061 has_changed_character = true;
5062 }
5063 current = next;
5064 }
5065 if (has_changed_character) {
5066 return result;
5067 } else {
5068 // If we didn't actually change anything in doing the conversion
5069 // we simple return the result and let the converted string
5070 // become garbage; there is no reason to keep two identical strings
5071 // alive.
5072 return s;
5073 }
5074}
5075
5076
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005077namespace {
5078
lrn@chromium.org303ada72010-10-27 09:33:13 +00005079static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF;
5080
5081
5082// Given a word and two range boundaries returns a word with high bit
5083// set in every byte iff the corresponding input byte was strictly in
5084// the range (m, n). All the other bits in the result are cleared.
5085// This function is only useful when it can be inlined and the
5086// boundaries are statically known.
5087// Requires: all bytes in the input word and the boundaries must be
5088// ascii (less than 0x7F).
5089static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
5090 // Every byte in an ascii string is less than or equal to 0x7F.
5091 ASSERT((w & (kOneInEveryByte * 0x7F)) == w);
5092 // Use strict inequalities since in edge cases the function could be
5093 // further simplified.
5094 ASSERT(0 < m && m < n && n < 0x7F);
5095 // Has high bit set in every w byte less than n.
5096 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w;
5097 // Has high bit set in every w byte greater than m.
5098 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m);
5099 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80));
5100}
5101
5102
5103enum AsciiCaseConversion {
5104 ASCII_TO_LOWER,
5105 ASCII_TO_UPPER
5106};
5107
5108
5109template <AsciiCaseConversion dir>
5110struct FastAsciiConverter {
5111 static bool Convert(char* dst, char* src, int length) {
5112#ifdef DEBUG
5113 char* saved_dst = dst;
5114 char* saved_src = src;
5115#endif
5116 // We rely on the distance between upper and lower case letters
5117 // being a known power of 2.
5118 ASSERT('a' - 'A' == (1 << 5));
5119 // Boundaries for the range of input characters than require conversion.
5120 const char lo = (dir == ASCII_TO_LOWER) ? 'A' - 1 : 'a' - 1;
5121 const char hi = (dir == ASCII_TO_LOWER) ? 'Z' + 1 : 'z' + 1;
5122 bool changed = false;
5123 char* const limit = src + length;
5124#ifdef V8_HOST_CAN_READ_UNALIGNED
5125 // Process the prefix of the input that requires no conversion one
5126 // (machine) word at a time.
5127 while (src <= limit - sizeof(uintptr_t)) {
5128 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
5129 if (AsciiRangeMask(w, lo, hi) != 0) {
5130 changed = true;
5131 break;
5132 }
5133 *reinterpret_cast<uintptr_t*>(dst) = w;
5134 src += sizeof(uintptr_t);
5135 dst += sizeof(uintptr_t);
5136 }
5137 // Process the remainder of the input performing conversion when
5138 // required one word at a time.
5139 while (src <= limit - sizeof(uintptr_t)) {
5140 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
5141 uintptr_t m = AsciiRangeMask(w, lo, hi);
5142 // The mask has high (7th) bit set in every byte that needs
5143 // conversion and we know that the distance between cases is
5144 // 1 << 5.
5145 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
5146 src += sizeof(uintptr_t);
5147 dst += sizeof(uintptr_t);
5148 }
5149#endif
5150 // Process the last few bytes of the input (or the whole input if
5151 // unaligned access is not supported).
5152 while (src < limit) {
5153 char c = *src;
5154 if (lo < c && c < hi) {
5155 c ^= (1 << 5);
5156 changed = true;
5157 }
5158 *dst = c;
5159 ++src;
5160 ++dst;
5161 }
5162#ifdef DEBUG
5163 CheckConvert(saved_dst, saved_src, length, changed);
5164#endif
5165 return changed;
5166 }
5167
5168#ifdef DEBUG
5169 static void CheckConvert(char* dst, char* src, int length, bool changed) {
5170 bool expected_changed = false;
5171 for (int i = 0; i < length; i++) {
5172 if (dst[i] == src[i]) continue;
5173 expected_changed = true;
5174 if (dir == ASCII_TO_LOWER) {
5175 ASSERT('A' <= src[i] && src[i] <= 'Z');
5176 ASSERT(dst[i] == src[i] + ('a' - 'A'));
5177 } else {
5178 ASSERT(dir == ASCII_TO_UPPER);
5179 ASSERT('a' <= src[i] && src[i] <= 'z');
5180 ASSERT(dst[i] == src[i] - ('a' - 'A'));
5181 }
5182 }
5183 ASSERT(expected_changed == changed);
5184 }
5185#endif
5186};
5187
5188
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005189struct ToLowerTraits {
5190 typedef unibrow::ToLowercase UnibrowConverter;
5191
lrn@chromium.org303ada72010-10-27 09:33:13 +00005192 typedef FastAsciiConverter<ASCII_TO_LOWER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005193};
5194
5195
5196struct ToUpperTraits {
5197 typedef unibrow::ToUppercase UnibrowConverter;
5198
lrn@chromium.org303ada72010-10-27 09:33:13 +00005199 typedef FastAsciiConverter<ASCII_TO_UPPER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005200};
5201
5202} // namespace
5203
5204
5205template <typename ConvertTraits>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005206MUST_USE_RESULT static MaybeObject* ConvertCase(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005207 Arguments args,
5208 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005209 NoHandleAllocation ha;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005210 CONVERT_CHECKED(String, s, args[0]);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005211 s = s->TryFlattenGetString();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005212
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005213 const int length = s->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005214 // Assume that the string is not empty; we need this assumption later
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005215 if (length == 0) return s;
5216
5217 // Simpler handling of ascii strings.
5218 //
5219 // NOTE: This assumes that the upper/lower case of an ascii
5220 // character is also ascii. This is currently the case, but it
5221 // might break in the future if we implement more context and locale
5222 // dependent upper/lower conversions.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005223 if (s->IsSeqAsciiString()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005224 Object* o;
5225 { MaybeObject* maybe_o = Heap::AllocateRawAsciiString(length);
5226 if (!maybe_o->ToObject(&o)) return maybe_o;
5227 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005228 SeqAsciiString* result = SeqAsciiString::cast(o);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005229 bool has_changed_character = ConvertTraits::AsciiConverter::Convert(
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005230 result->GetChars(), SeqAsciiString::cast(s)->GetChars(), length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005231 return has_changed_character ? result : s;
5232 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005233
lrn@chromium.org303ada72010-10-27 09:33:13 +00005234 Object* answer;
5235 { MaybeObject* maybe_answer = ConvertCaseHelper(s, length, length, mapping);
5236 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5237 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005238 if (answer->IsSmi()) {
5239 // Retry with correct length.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005240 { MaybeObject* maybe_answer =
5241 ConvertCaseHelper(s, Smi::cast(answer)->value(), length, mapping);
5242 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5243 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005244 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00005245 return answer;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005246}
5247
5248
lrn@chromium.org303ada72010-10-27 09:33:13 +00005249static MaybeObject* Runtime_StringToLowerCase(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005250 return ConvertCase<ToLowerTraits>(args, &to_lower_mapping);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005251}
5252
5253
lrn@chromium.org303ada72010-10-27 09:33:13 +00005254static MaybeObject* Runtime_StringToUpperCase(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005255 return ConvertCase<ToUpperTraits>(args, &to_upper_mapping);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005256}
5257
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005258
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005259static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
5260 return unibrow::WhiteSpace::Is(c) || c == 0x200b;
5261}
5262
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005263
lrn@chromium.org303ada72010-10-27 09:33:13 +00005264static MaybeObject* Runtime_StringTrim(Arguments args) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005265 NoHandleAllocation ha;
5266 ASSERT(args.length() == 3);
5267
5268 CONVERT_CHECKED(String, s, args[0]);
5269 CONVERT_BOOLEAN_CHECKED(trimLeft, args[1]);
5270 CONVERT_BOOLEAN_CHECKED(trimRight, args[2]);
5271
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005272 s->TryFlatten();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005273 int length = s->length();
5274
5275 int left = 0;
5276 if (trimLeft) {
5277 while (left < length && IsTrimWhiteSpace(s->Get(left))) {
5278 left++;
5279 }
5280 }
5281
5282 int right = length;
5283 if (trimRight) {
5284 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) {
5285 right--;
5286 }
5287 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005288 return s->SubString(left, right);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005289}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005290
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005291
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005292template <typename SubjectChar, typename PatternChar>
5293void FindStringIndices(Vector<const SubjectChar> subject,
5294 Vector<const PatternChar> pattern,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005295 ZoneList<int>* indices,
5296 unsigned int limit) {
5297 ASSERT(limit > 0);
5298 // Collect indices of pattern in subject, and the end-of-string index.
5299 // Stop after finding at most limit values.
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005300 StringSearch<PatternChar, SubjectChar> search(pattern);
5301 int pattern_length = pattern.length();
5302 int index = 0;
5303 while (limit > 0) {
5304 index = search.Search(subject, index);
5305 if (index < 0) return;
5306 indices->Add(index);
5307 index += pattern_length;
5308 limit--;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005309 }
5310}
5311
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005312
lrn@chromium.org303ada72010-10-27 09:33:13 +00005313static MaybeObject* Runtime_StringSplit(Arguments args) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005314 ASSERT(args.length() == 3);
5315 HandleScope handle_scope;
5316 CONVERT_ARG_CHECKED(String, subject, 0);
5317 CONVERT_ARG_CHECKED(String, pattern, 1);
5318 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
5319
5320 int subject_length = subject->length();
5321 int pattern_length = pattern->length();
5322 RUNTIME_ASSERT(pattern_length > 0);
5323
5324 // The limit can be very large (0xffffffffu), but since the pattern
5325 // isn't empty, we can never create more parts than ~half the length
5326 // of the subject.
5327
5328 if (!subject->IsFlat()) FlattenString(subject);
5329
5330 static const int kMaxInitialListCapacity = 16;
5331
5332 ZoneScope scope(DELETE_ON_EXIT);
5333
5334 // Find (up to limit) indices of separator and end-of-string in subject
5335 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
5336 ZoneList<int> indices(initial_capacity);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005337 if (!pattern->IsFlat()) FlattenString(pattern);
5338
5339 // No allocation block.
5340 {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005341 AssertNoAllocation nogc;
5342 if (subject->IsAsciiRepresentation()) {
5343 Vector<const char> subject_vector = subject->ToAsciiVector();
5344 if (pattern->IsAsciiRepresentation()) {
5345 FindStringIndices(subject_vector,
5346 pattern->ToAsciiVector(),
5347 &indices,
5348 limit);
5349 } else {
5350 FindStringIndices(subject_vector,
5351 pattern->ToUC16Vector(),
5352 &indices,
5353 limit);
5354 }
5355 } else {
5356 Vector<const uc16> subject_vector = subject->ToUC16Vector();
5357 if (pattern->IsAsciiRepresentation()) {
5358 FindStringIndices(subject_vector,
5359 pattern->ToAsciiVector(),
5360 &indices,
5361 limit);
5362 } else {
5363 FindStringIndices(subject_vector,
5364 pattern->ToUC16Vector(),
5365 &indices,
5366 limit);
5367 }
5368 }
5369 }
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005370
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005371 if (static_cast<uint32_t>(indices.length()) < limit) {
5372 indices.Add(subject_length);
5373 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005374
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005375 // The list indices now contains the end of each part to create.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005376
5377 // Create JSArray of substrings separated by separator.
5378 int part_count = indices.length();
5379
5380 Handle<JSArray> result = Factory::NewJSArray(part_count);
5381 result->set_length(Smi::FromInt(part_count));
5382
5383 ASSERT(result->HasFastElements());
5384
5385 if (part_count == 1 && indices.at(0) == subject_length) {
5386 FixedArray::cast(result->elements())->set(0, *subject);
5387 return *result;
5388 }
5389
5390 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
5391 int part_start = 0;
5392 for (int i = 0; i < part_count; i++) {
5393 HandleScope local_loop_handle;
5394 int part_end = indices.at(i);
5395 Handle<String> substring =
5396 Factory::NewSubString(subject, part_start, part_end);
5397 elements->set(i, *substring);
5398 part_start = part_end + pattern_length;
5399 }
5400
5401 return *result;
5402}
5403
5404
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005405// Copies ascii characters to the given fixed array looking up
5406// one-char strings in the cache. Gives up on the first char that is
5407// not in the cache and fills the remainder with smi zeros. Returns
5408// the length of the successfully copied prefix.
5409static int CopyCachedAsciiCharsToArray(const char* chars,
5410 FixedArray* elements,
5411 int length) {
5412 AssertNoAllocation nogc;
5413 FixedArray* ascii_cache = Heap::single_character_string_cache();
5414 Object* undefined = Heap::undefined_value();
5415 int i;
5416 for (i = 0; i < length; ++i) {
5417 Object* value = ascii_cache->get(chars[i]);
5418 if (value == undefined) break;
5419 ASSERT(!Heap::InNewSpace(value));
5420 elements->set(i, value, SKIP_WRITE_BARRIER);
5421 }
5422 if (i < length) {
5423 ASSERT(Smi::FromInt(0) == 0);
5424 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
5425 }
5426#ifdef DEBUG
5427 for (int j = 0; j < length; ++j) {
5428 Object* element = elements->get(j);
5429 ASSERT(element == Smi::FromInt(0) ||
5430 (element->IsString() && String::cast(element)->LooksValid()));
5431 }
5432#endif
5433 return i;
5434}
5435
5436
5437// Converts a String to JSArray.
5438// For example, "foo" => ["f", "o", "o"].
lrn@chromium.org303ada72010-10-27 09:33:13 +00005439static MaybeObject* Runtime_StringToArray(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005440 HandleScope scope;
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005441 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005442 CONVERT_ARG_CHECKED(String, s, 0);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005443 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005444
5445 s->TryFlatten();
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005446 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005447
5448 Handle<FixedArray> elements;
5449 if (s->IsFlat() && s->IsAsciiRepresentation()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005450 Object* obj;
5451 { MaybeObject* maybe_obj = Heap::AllocateUninitializedFixedArray(length);
5452 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5453 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005454 elements = Handle<FixedArray>(FixedArray::cast(obj));
5455
5456 Vector<const char> chars = s->ToAsciiVector();
5457 // Note, this will initialize all elements (not only the prefix)
5458 // to prevent GC from seeing partially initialized array.
5459 int num_copied_from_cache = CopyCachedAsciiCharsToArray(chars.start(),
5460 *elements,
5461 length);
5462
5463 for (int i = num_copied_from_cache; i < length; ++i) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00005464 Handle<Object> str = LookupSingleCharacterStringFromCode(chars[i]);
5465 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005466 }
5467 } else {
5468 elements = Factory::NewFixedArray(length);
5469 for (int i = 0; i < length; ++i) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00005470 Handle<Object> str = LookupSingleCharacterStringFromCode(s->Get(i));
5471 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005472 }
5473 }
5474
5475#ifdef DEBUG
5476 for (int i = 0; i < length; ++i) {
5477 ASSERT(String::cast(elements->get(i))->length() == 1);
5478 }
5479#endif
5480
5481 return *Factory::NewJSArrayWithElements(elements);
5482}
5483
5484
lrn@chromium.org303ada72010-10-27 09:33:13 +00005485static MaybeObject* Runtime_NewStringWrapper(Arguments args) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005486 NoHandleAllocation ha;
5487 ASSERT(args.length() == 1);
5488 CONVERT_CHECKED(String, value, args[0]);
5489 return value->ToObject();
5490}
5491
5492
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00005493bool Runtime::IsUpperCaseChar(uint16_t ch) {
5494 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
5495 int char_length = to_upper_mapping.get(ch, 0, chars);
5496 return char_length == 0;
5497}
5498
5499
lrn@chromium.org303ada72010-10-27 09:33:13 +00005500static MaybeObject* Runtime_NumberToString(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005501 NoHandleAllocation ha;
5502 ASSERT(args.length() == 1);
5503
5504 Object* number = args[0];
5505 RUNTIME_ASSERT(number->IsNumber());
5506
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005507 return Heap::NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005508}
5509
5510
lrn@chromium.org303ada72010-10-27 09:33:13 +00005511static MaybeObject* Runtime_NumberToStringSkipCache(Arguments args) {
ager@chromium.org357bf652010-04-12 11:30:10 +00005512 NoHandleAllocation ha;
5513 ASSERT(args.length() == 1);
5514
5515 Object* number = args[0];
5516 RUNTIME_ASSERT(number->IsNumber());
5517
5518 return Heap::NumberToString(number, false);
5519}
5520
5521
lrn@chromium.org303ada72010-10-27 09:33:13 +00005522static MaybeObject* Runtime_NumberToInteger(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005523 NoHandleAllocation ha;
5524 ASSERT(args.length() == 1);
5525
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005526 CONVERT_DOUBLE_CHECKED(number, args[0]);
5527
5528 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5529 if (number > 0 && number <= Smi::kMaxValue) {
5530 return Smi::FromInt(static_cast<int>(number));
5531 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005532 return Heap::NumberFromDouble(DoubleToInteger(number));
5533}
5534
5535
lrn@chromium.org303ada72010-10-27 09:33:13 +00005536static MaybeObject* Runtime_NumberToIntegerMapMinusZero(Arguments args) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005537 NoHandleAllocation ha;
5538 ASSERT(args.length() == 1);
5539
5540 CONVERT_DOUBLE_CHECKED(number, args[0]);
5541
5542 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5543 if (number > 0 && number <= Smi::kMaxValue) {
5544 return Smi::FromInt(static_cast<int>(number));
5545 }
5546
5547 double double_value = DoubleToInteger(number);
5548 // Map both -0 and +0 to +0.
5549 if (double_value == 0) double_value = 0;
5550
5551 return Heap::NumberFromDouble(double_value);
5552}
5553
5554
lrn@chromium.org303ada72010-10-27 09:33:13 +00005555static MaybeObject* Runtime_NumberToJSUint32(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005556 NoHandleAllocation ha;
5557 ASSERT(args.length() == 1);
5558
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005559 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005560 return Heap::NumberFromUint32(number);
5561}
5562
5563
lrn@chromium.org303ada72010-10-27 09:33:13 +00005564static MaybeObject* Runtime_NumberToJSInt32(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005565 NoHandleAllocation ha;
5566 ASSERT(args.length() == 1);
5567
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005568 CONVERT_DOUBLE_CHECKED(number, args[0]);
5569
5570 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5571 if (number > 0 && number <= Smi::kMaxValue) {
5572 return Smi::FromInt(static_cast<int>(number));
5573 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005574 return Heap::NumberFromInt32(DoubleToInt32(number));
5575}
5576
5577
ager@chromium.org870a0b62008-11-04 11:43:05 +00005578// Converts a Number to a Smi, if possible. Returns NaN if the number is not
5579// a small integer.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005580static MaybeObject* Runtime_NumberToSmi(Arguments args) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00005581 NoHandleAllocation ha;
5582 ASSERT(args.length() == 1);
5583
5584 Object* obj = args[0];
5585 if (obj->IsSmi()) {
5586 return obj;
5587 }
5588 if (obj->IsHeapNumber()) {
5589 double value = HeapNumber::cast(obj)->value();
5590 int int_value = FastD2I(value);
5591 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
5592 return Smi::FromInt(int_value);
5593 }
5594 }
5595 return Heap::nan_value();
5596}
5597
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005598
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005599static MaybeObject* Runtime_AllocateHeapNumber(Arguments args) {
5600 NoHandleAllocation ha;
5601 ASSERT(args.length() == 0);
5602 return Heap::AllocateHeapNumber(0);
5603}
5604
5605
lrn@chromium.org303ada72010-10-27 09:33:13 +00005606static MaybeObject* Runtime_NumberAdd(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005607 NoHandleAllocation ha;
5608 ASSERT(args.length() == 2);
5609
5610 CONVERT_DOUBLE_CHECKED(x, args[0]);
5611 CONVERT_DOUBLE_CHECKED(y, args[1]);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00005612 return Heap::NumberFromDouble(x + y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005613}
5614
5615
lrn@chromium.org303ada72010-10-27 09:33:13 +00005616static MaybeObject* Runtime_NumberSub(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005617 NoHandleAllocation ha;
5618 ASSERT(args.length() == 2);
5619
5620 CONVERT_DOUBLE_CHECKED(x, args[0]);
5621 CONVERT_DOUBLE_CHECKED(y, args[1]);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00005622 return Heap::NumberFromDouble(x - y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005623}
5624
5625
lrn@chromium.org303ada72010-10-27 09:33:13 +00005626static MaybeObject* Runtime_NumberMul(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005627 NoHandleAllocation ha;
5628 ASSERT(args.length() == 2);
5629
5630 CONVERT_DOUBLE_CHECKED(x, args[0]);
5631 CONVERT_DOUBLE_CHECKED(y, args[1]);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00005632 return Heap::NumberFromDouble(x * y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005633}
5634
5635
lrn@chromium.org303ada72010-10-27 09:33:13 +00005636static MaybeObject* Runtime_NumberUnaryMinus(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005637 NoHandleAllocation ha;
5638 ASSERT(args.length() == 1);
5639
5640 CONVERT_DOUBLE_CHECKED(x, args[0]);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00005641 return Heap::NumberFromDouble(-x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005642}
5643
5644
lrn@chromium.org303ada72010-10-27 09:33:13 +00005645static MaybeObject* Runtime_NumberAlloc(Arguments args) {
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00005646 NoHandleAllocation ha;
5647 ASSERT(args.length() == 0);
5648
5649 return Heap::NumberFromDouble(9876543210.0);
5650}
5651
5652
lrn@chromium.org303ada72010-10-27 09:33:13 +00005653static MaybeObject* Runtime_NumberDiv(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005654 NoHandleAllocation ha;
5655 ASSERT(args.length() == 2);
5656
5657 CONVERT_DOUBLE_CHECKED(x, args[0]);
5658 CONVERT_DOUBLE_CHECKED(y, args[1]);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00005659 return Heap::NumberFromDouble(x / y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005660}
5661
5662
lrn@chromium.org303ada72010-10-27 09:33:13 +00005663static MaybeObject* Runtime_NumberMod(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005664 NoHandleAllocation ha;
5665 ASSERT(args.length() == 2);
5666
5667 CONVERT_DOUBLE_CHECKED(x, args[0]);
5668 CONVERT_DOUBLE_CHECKED(y, args[1]);
5669
ager@chromium.org3811b432009-10-28 14:53:37 +00005670 x = modulo(x, y);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00005671 // NumberFromDouble may return a Smi instead of a Number object
5672 return Heap::NumberFromDouble(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005673}
5674
5675
lrn@chromium.org303ada72010-10-27 09:33:13 +00005676static MaybeObject* Runtime_StringAdd(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005677 NoHandleAllocation ha;
5678 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005679 CONVERT_CHECKED(String, str1, args[0]);
5680 CONVERT_CHECKED(String, str2, args[1]);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00005681 Counters::string_add_runtime.Increment();
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00005682 return Heap::AllocateConsString(str1, str2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005683}
5684
5685
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005686template <typename sinkchar>
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005687static inline void StringBuilderConcatHelper(String* special,
5688 sinkchar* sink,
5689 FixedArray* fixed_array,
5690 int array_length) {
5691 int position = 0;
5692 for (int i = 0; i < array_length; i++) {
5693 Object* element = fixed_array->get(i);
5694 if (element->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005695 // Smi encoding of position and length.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005696 int encoded_slice = Smi::cast(element)->value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005697 int pos;
5698 int len;
5699 if (encoded_slice > 0) {
5700 // Position and length encoded in one smi.
5701 pos = StringBuilderSubstringPosition::decode(encoded_slice);
5702 len = StringBuilderSubstringLength::decode(encoded_slice);
5703 } else {
5704 // Position and length encoded in two smis.
5705 Object* obj = fixed_array->get(++i);
5706 ASSERT(obj->IsSmi());
5707 pos = Smi::cast(obj)->value();
5708 len = -encoded_slice;
5709 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00005710 String::WriteToFlat(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00005711 sink + position,
5712 pos,
5713 pos + len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005714 position += len;
5715 } else {
5716 String* string = String::cast(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005717 int element_length = string->length();
5718 String::WriteToFlat(string, sink + position, 0, element_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005719 position += element_length;
5720 }
5721 }
5722}
5723
5724
lrn@chromium.org303ada72010-10-27 09:33:13 +00005725static MaybeObject* Runtime_StringBuilderConcat(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005726 NoHandleAllocation ha;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005727 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005728 CONVERT_CHECKED(JSArray, array, args[0]);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005729 if (!args[1]->IsSmi()) {
5730 Top::context()->mark_out_of_memory();
5731 return Failure::OutOfMemoryException();
5732 }
5733 int array_length = Smi::cast(args[1])->value();
5734 CONVERT_CHECKED(String, special, args[2]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005735
5736 // This assumption is used by the slice encoding in one or two smis.
5737 ASSERT(Smi::kMaxValue >= String::kMaxLength);
5738
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005739 int special_length = special->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005740 if (!array->HasFastElements()) {
5741 return Top::Throw(Heap::illegal_argument_symbol());
5742 }
5743 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005744 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005745 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005746 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005747
5748 if (array_length == 0) {
5749 return Heap::empty_string();
5750 } else if (array_length == 1) {
5751 Object* first = fixed_array->get(0);
5752 if (first->IsString()) return first;
5753 }
5754
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005755 bool ascii = special->HasOnlyAsciiChars();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005756 int position = 0;
5757 for (int i = 0; i < array_length; i++) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005758 int increment = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005759 Object* elt = fixed_array->get(i);
5760 if (elt->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005761 // Smi encoding of position and length.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005762 int smi_value = Smi::cast(elt)->value();
5763 int pos;
5764 int len;
5765 if (smi_value > 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005766 // Position and length encoded in one smi.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005767 pos = StringBuilderSubstringPosition::decode(smi_value);
5768 len = StringBuilderSubstringLength::decode(smi_value);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005769 } else {
5770 // Position and length encoded in two smis.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005771 len = -smi_value;
5772 // Get the position and check that it is a positive smi.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005773 i++;
5774 if (i >= array_length) {
5775 return Top::Throw(Heap::illegal_argument_symbol());
5776 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005777 Object* next_smi = fixed_array->get(i);
5778 if (!next_smi->IsSmi()) {
5779 return Top::Throw(Heap::illegal_argument_symbol());
5780 }
5781 pos = Smi::cast(next_smi)->value();
5782 if (pos < 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005783 return Top::Throw(Heap::illegal_argument_symbol());
5784 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005785 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005786 ASSERT(pos >= 0);
5787 ASSERT(len >= 0);
5788 if (pos > special_length || len > special_length - pos) {
5789 return Top::Throw(Heap::illegal_argument_symbol());
5790 }
5791 increment = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005792 } else if (elt->IsString()) {
5793 String* element = String::cast(elt);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005794 int element_length = element->length();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005795 increment = element_length;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005796 if (ascii && !element->HasOnlyAsciiChars()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005797 ascii = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005798 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005799 } else {
5800 return Top::Throw(Heap::illegal_argument_symbol());
5801 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005802 if (increment > String::kMaxLength - position) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005803 Top::context()->mark_out_of_memory();
5804 return Failure::OutOfMemoryException();
5805 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005806 position += increment;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005807 }
5808
5809 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005810 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005811
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005812 if (ascii) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005813 { MaybeObject* maybe_object = Heap::AllocateRawAsciiString(length);
5814 if (!maybe_object->ToObject(&object)) return maybe_object;
5815 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005816 SeqAsciiString* answer = SeqAsciiString::cast(object);
5817 StringBuilderConcatHelper(special,
5818 answer->GetChars(),
5819 fixed_array,
5820 array_length);
5821 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005822 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005823 { MaybeObject* maybe_object = Heap::AllocateRawTwoByteString(length);
5824 if (!maybe_object->ToObject(&object)) return maybe_object;
5825 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005826 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
5827 StringBuilderConcatHelper(special,
5828 answer->GetChars(),
5829 fixed_array,
5830 array_length);
5831 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005832 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005833}
5834
5835
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00005836static MaybeObject* Runtime_StringBuilderJoin(Arguments args) {
5837 NoHandleAllocation ha;
5838 ASSERT(args.length() == 3);
5839 CONVERT_CHECKED(JSArray, array, args[0]);
5840 if (!args[1]->IsSmi()) {
5841 Top::context()->mark_out_of_memory();
5842 return Failure::OutOfMemoryException();
5843 }
5844 int array_length = Smi::cast(args[1])->value();
5845 CONVERT_CHECKED(String, separator, args[2]);
5846
5847 if (!array->HasFastElements()) {
5848 return Top::Throw(Heap::illegal_argument_symbol());
5849 }
5850 FixedArray* fixed_array = FixedArray::cast(array->elements());
5851 if (fixed_array->length() < array_length) {
5852 array_length = fixed_array->length();
5853 }
5854
5855 if (array_length == 0) {
5856 return Heap::empty_string();
5857 } else if (array_length == 1) {
5858 Object* first = fixed_array->get(0);
5859 if (first->IsString()) return first;
5860 }
5861
5862 int separator_length = separator->length();
5863 int max_nof_separators =
5864 (String::kMaxLength + separator_length - 1) / separator_length;
5865 if (max_nof_separators < (array_length - 1)) {
5866 Top::context()->mark_out_of_memory();
5867 return Failure::OutOfMemoryException();
5868 }
5869 int length = (array_length - 1) * separator_length;
5870 for (int i = 0; i < array_length; i++) {
5871 Object* element_obj = fixed_array->get(i);
5872 if (!element_obj->IsString()) {
5873 // TODO(1161): handle this case.
5874 return Top::Throw(Heap::illegal_argument_symbol());
5875 }
5876 String* element = String::cast(element_obj);
5877 int increment = element->length();
5878 if (increment > String::kMaxLength - length) {
5879 Top::context()->mark_out_of_memory();
5880 return Failure::OutOfMemoryException();
5881 }
5882 length += increment;
5883 }
5884
5885 Object* object;
5886 { MaybeObject* maybe_object = Heap::AllocateRawTwoByteString(length);
5887 if (!maybe_object->ToObject(&object)) return maybe_object;
5888 }
5889 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
5890
5891 uc16* sink = answer->GetChars();
5892#ifdef DEBUG
5893 uc16* end = sink + length;
5894#endif
5895
5896 String* first = String::cast(fixed_array->get(0));
5897 int first_length = first->length();
5898 String::WriteToFlat(first, sink, 0, first_length);
5899 sink += first_length;
5900
5901 for (int i = 1; i < array_length; i++) {
5902 ASSERT(sink + separator_length <= end);
5903 String::WriteToFlat(separator, sink, 0, separator_length);
5904 sink += separator_length;
5905
5906 String* element = String::cast(fixed_array->get(i));
5907 int element_length = element->length();
5908 ASSERT(sink + element_length <= end);
5909 String::WriteToFlat(element, sink, 0, element_length);
5910 sink += element_length;
5911 }
5912 ASSERT(sink == end);
5913
5914 ASSERT(!answer->HasOnlyAsciiChars()); // Use %_FastAsciiArrayJoin instead.
5915 return answer;
5916}
5917
5918
lrn@chromium.org303ada72010-10-27 09:33:13 +00005919static MaybeObject* Runtime_NumberOr(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005920 NoHandleAllocation ha;
5921 ASSERT(args.length() == 2);
5922
5923 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5924 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5925 return Heap::NumberFromInt32(x | y);
5926}
5927
5928
lrn@chromium.org303ada72010-10-27 09:33:13 +00005929static MaybeObject* Runtime_NumberAnd(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005930 NoHandleAllocation ha;
5931 ASSERT(args.length() == 2);
5932
5933 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5934 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5935 return Heap::NumberFromInt32(x & y);
5936}
5937
5938
lrn@chromium.org303ada72010-10-27 09:33:13 +00005939static MaybeObject* Runtime_NumberXor(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005940 NoHandleAllocation ha;
5941 ASSERT(args.length() == 2);
5942
5943 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5944 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5945 return Heap::NumberFromInt32(x ^ y);
5946}
5947
5948
lrn@chromium.org303ada72010-10-27 09:33:13 +00005949static MaybeObject* Runtime_NumberNot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005950 NoHandleAllocation ha;
5951 ASSERT(args.length() == 1);
5952
5953 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5954 return Heap::NumberFromInt32(~x);
5955}
5956
5957
lrn@chromium.org303ada72010-10-27 09:33:13 +00005958static MaybeObject* Runtime_NumberShl(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005959 NoHandleAllocation ha;
5960 ASSERT(args.length() == 2);
5961
5962 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5963 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5964 return Heap::NumberFromInt32(x << (y & 0x1f));
5965}
5966
5967
lrn@chromium.org303ada72010-10-27 09:33:13 +00005968static MaybeObject* Runtime_NumberShr(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005969 NoHandleAllocation ha;
5970 ASSERT(args.length() == 2);
5971
5972 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
5973 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5974 return Heap::NumberFromUint32(x >> (y & 0x1f));
5975}
5976
5977
lrn@chromium.org303ada72010-10-27 09:33:13 +00005978static MaybeObject* Runtime_NumberSar(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005979 NoHandleAllocation ha;
5980 ASSERT(args.length() == 2);
5981
5982 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5983 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5984 return Heap::NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
5985}
5986
5987
lrn@chromium.org303ada72010-10-27 09:33:13 +00005988static MaybeObject* Runtime_NumberEquals(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005989 NoHandleAllocation ha;
5990 ASSERT(args.length() == 2);
5991
5992 CONVERT_DOUBLE_CHECKED(x, args[0]);
5993 CONVERT_DOUBLE_CHECKED(y, args[1]);
5994 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
5995 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
5996 if (x == y) return Smi::FromInt(EQUAL);
5997 Object* result;
5998 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
5999 result = Smi::FromInt(EQUAL);
6000 } else {
6001 result = Smi::FromInt(NOT_EQUAL);
6002 }
6003 return result;
6004}
6005
6006
lrn@chromium.org303ada72010-10-27 09:33:13 +00006007static MaybeObject* Runtime_StringEquals(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006008 NoHandleAllocation ha;
6009 ASSERT(args.length() == 2);
6010
6011 CONVERT_CHECKED(String, x, args[0]);
6012 CONVERT_CHECKED(String, y, args[1]);
6013
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006014 bool not_equal = !x->Equals(y);
6015 // This is slightly convoluted because the value that signifies
6016 // equality is 0 and inequality is 1 so we have to negate the result
6017 // from String::Equals.
6018 ASSERT(not_equal == 0 || not_equal == 1);
6019 STATIC_CHECK(EQUAL == 0);
6020 STATIC_CHECK(NOT_EQUAL == 1);
6021 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006022}
6023
6024
lrn@chromium.org303ada72010-10-27 09:33:13 +00006025static MaybeObject* Runtime_NumberCompare(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006026 NoHandleAllocation ha;
6027 ASSERT(args.length() == 3);
6028
6029 CONVERT_DOUBLE_CHECKED(x, args[0]);
6030 CONVERT_DOUBLE_CHECKED(y, args[1]);
6031 if (isnan(x) || isnan(y)) return args[2];
6032 if (x == y) return Smi::FromInt(EQUAL);
6033 if (isless(x, y)) return Smi::FromInt(LESS);
6034 return Smi::FromInt(GREATER);
6035}
6036
6037
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006038// Compare two Smis as if they were converted to strings and then
6039// compared lexicographically.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006040static MaybeObject* Runtime_SmiLexicographicCompare(Arguments args) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006041 NoHandleAllocation ha;
6042 ASSERT(args.length() == 2);
6043
6044 // Arrays for the individual characters of the two Smis. Smis are
6045 // 31 bit integers and 10 decimal digits are therefore enough.
6046 static int x_elms[10];
6047 static int y_elms[10];
6048
6049 // Extract the integer values from the Smis.
6050 CONVERT_CHECKED(Smi, x, args[0]);
6051 CONVERT_CHECKED(Smi, y, args[1]);
6052 int x_value = x->value();
6053 int y_value = y->value();
6054
6055 // If the integers are equal so are the string representations.
6056 if (x_value == y_value) return Smi::FromInt(EQUAL);
6057
6058 // If one of the integers are zero the normal integer order is the
6059 // same as the lexicographic order of the string representations.
6060 if (x_value == 0 || y_value == 0) return Smi::FromInt(x_value - y_value);
6061
ager@chromium.org32912102009-01-16 10:38:43 +00006062 // If only one of the integers is negative the negative number is
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006063 // smallest because the char code of '-' is less than the char code
6064 // of any digit. Otherwise, we make both values positive.
6065 if (x_value < 0 || y_value < 0) {
6066 if (y_value >= 0) return Smi::FromInt(LESS);
6067 if (x_value >= 0) return Smi::FromInt(GREATER);
6068 x_value = -x_value;
6069 y_value = -y_value;
6070 }
6071
6072 // Convert the integers to arrays of their decimal digits.
6073 int x_index = 0;
6074 int y_index = 0;
6075 while (x_value > 0) {
6076 x_elms[x_index++] = x_value % 10;
6077 x_value /= 10;
6078 }
6079 while (y_value > 0) {
6080 y_elms[y_index++] = y_value % 10;
6081 y_value /= 10;
6082 }
6083
6084 // Loop through the arrays of decimal digits finding the first place
6085 // where they differ.
6086 while (--x_index >= 0 && --y_index >= 0) {
6087 int diff = x_elms[x_index] - y_elms[y_index];
6088 if (diff != 0) return Smi::FromInt(diff);
6089 }
6090
6091 // If one array is a suffix of the other array, the longest array is
6092 // the representation of the largest of the Smis in the
6093 // lexicographic ordering.
6094 return Smi::FromInt(x_index - y_index);
6095}
6096
6097
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006098static Object* StringInputBufferCompare(String* x, String* y) {
6099 static StringInputBuffer bufx;
6100 static StringInputBuffer bufy;
6101 bufx.Reset(x);
6102 bufy.Reset(y);
6103 while (bufx.has_more() && bufy.has_more()) {
6104 int d = bufx.GetNext() - bufy.GetNext();
6105 if (d < 0) return Smi::FromInt(LESS);
6106 else if (d > 0) return Smi::FromInt(GREATER);
6107 }
6108
6109 // x is (non-trivial) prefix of y:
6110 if (bufy.has_more()) return Smi::FromInt(LESS);
6111 // y is prefix of x:
6112 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
6113}
6114
6115
6116static Object* FlatStringCompare(String* x, String* y) {
6117 ASSERT(x->IsFlat());
6118 ASSERT(y->IsFlat());
6119 Object* equal_prefix_result = Smi::FromInt(EQUAL);
6120 int prefix_length = x->length();
6121 if (y->length() < prefix_length) {
6122 prefix_length = y->length();
6123 equal_prefix_result = Smi::FromInt(GREATER);
6124 } else if (y->length() > prefix_length) {
6125 equal_prefix_result = Smi::FromInt(LESS);
6126 }
6127 int r;
6128 if (x->IsAsciiRepresentation()) {
6129 Vector<const char> x_chars = x->ToAsciiVector();
6130 if (y->IsAsciiRepresentation()) {
6131 Vector<const char> y_chars = y->ToAsciiVector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006132 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006133 } else {
6134 Vector<const uc16> y_chars = y->ToUC16Vector();
6135 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6136 }
6137 } else {
6138 Vector<const uc16> x_chars = x->ToUC16Vector();
6139 if (y->IsAsciiRepresentation()) {
6140 Vector<const char> y_chars = y->ToAsciiVector();
6141 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6142 } else {
6143 Vector<const uc16> y_chars = y->ToUC16Vector();
6144 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6145 }
6146 }
6147 Object* result;
6148 if (r == 0) {
6149 result = equal_prefix_result;
6150 } else {
6151 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
6152 }
6153 ASSERT(result == StringInputBufferCompare(x, y));
6154 return result;
6155}
6156
6157
lrn@chromium.org303ada72010-10-27 09:33:13 +00006158static MaybeObject* Runtime_StringCompare(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006159 NoHandleAllocation ha;
6160 ASSERT(args.length() == 2);
6161
6162 CONVERT_CHECKED(String, x, args[0]);
6163 CONVERT_CHECKED(String, y, args[1]);
6164
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006165 Counters::string_compare_runtime.Increment();
6166
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006167 // A few fast case tests before we flatten.
6168 if (x == y) return Smi::FromInt(EQUAL);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006169 if (y->length() == 0) {
6170 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006171 return Smi::FromInt(GREATER);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006172 } else if (x->length() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006173 return Smi::FromInt(LESS);
6174 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006175
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006176 int d = x->Get(0) - y->Get(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006177 if (d < 0) return Smi::FromInt(LESS);
6178 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006179
lrn@chromium.org303ada72010-10-27 09:33:13 +00006180 Object* obj;
6181 { MaybeObject* maybe_obj = Heap::PrepareForCompare(x);
6182 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6183 }
6184 { MaybeObject* maybe_obj = Heap::PrepareForCompare(y);
6185 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6186 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006187
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006188 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
6189 : StringInputBufferCompare(x, y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006190}
6191
6192
lrn@chromium.org303ada72010-10-27 09:33:13 +00006193static MaybeObject* Runtime_Math_acos(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006194 NoHandleAllocation ha;
6195 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006196 Counters::math_acos.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006197
6198 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006199 return TranscendentalCache::Get(TranscendentalCache::ACOS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006200}
6201
6202
lrn@chromium.org303ada72010-10-27 09:33:13 +00006203static MaybeObject* Runtime_Math_asin(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006204 NoHandleAllocation ha;
6205 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006206 Counters::math_asin.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006207
6208 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006209 return TranscendentalCache::Get(TranscendentalCache::ASIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006210}
6211
6212
lrn@chromium.org303ada72010-10-27 09:33:13 +00006213static MaybeObject* Runtime_Math_atan(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006214 NoHandleAllocation ha;
6215 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006216 Counters::math_atan.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006217
6218 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006219 return TranscendentalCache::Get(TranscendentalCache::ATAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006220}
6221
6222
lrn@chromium.org303ada72010-10-27 09:33:13 +00006223static MaybeObject* Runtime_Math_atan2(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006224 NoHandleAllocation ha;
6225 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006226 Counters::math_atan2.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006227
6228 CONVERT_DOUBLE_CHECKED(x, args[0]);
6229 CONVERT_DOUBLE_CHECKED(y, args[1]);
6230 double result;
6231 if (isinf(x) && isinf(y)) {
6232 // Make sure that the result in case of two infinite arguments
6233 // is a multiple of Pi / 4. The sign of the result is determined
6234 // by the first argument (x) and the sign of the second argument
6235 // determines the multiplier: one or three.
6236 static double kPiDividedBy4 = 0.78539816339744830962;
6237 int multiplier = (x < 0) ? -1 : 1;
6238 if (y < 0) multiplier *= 3;
6239 result = multiplier * kPiDividedBy4;
6240 } else {
6241 result = atan2(x, y);
6242 }
6243 return Heap::AllocateHeapNumber(result);
6244}
6245
6246
lrn@chromium.org303ada72010-10-27 09:33:13 +00006247static MaybeObject* Runtime_Math_ceil(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006248 NoHandleAllocation ha;
6249 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006250 Counters::math_ceil.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006251
6252 CONVERT_DOUBLE_CHECKED(x, args[0]);
6253 return Heap::NumberFromDouble(ceiling(x));
6254}
6255
6256
lrn@chromium.org303ada72010-10-27 09:33:13 +00006257static MaybeObject* Runtime_Math_cos(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006258 NoHandleAllocation ha;
6259 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006260 Counters::math_cos.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006261
6262 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006263 return TranscendentalCache::Get(TranscendentalCache::COS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006264}
6265
6266
lrn@chromium.org303ada72010-10-27 09:33:13 +00006267static MaybeObject* Runtime_Math_exp(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006268 NoHandleAllocation ha;
6269 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006270 Counters::math_exp.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006271
6272 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006273 return TranscendentalCache::Get(TranscendentalCache::EXP, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006274}
6275
6276
lrn@chromium.org303ada72010-10-27 09:33:13 +00006277static MaybeObject* Runtime_Math_floor(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006278 NoHandleAllocation ha;
6279 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006280 Counters::math_floor.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006281
6282 CONVERT_DOUBLE_CHECKED(x, args[0]);
6283 return Heap::NumberFromDouble(floor(x));
6284}
6285
6286
lrn@chromium.org303ada72010-10-27 09:33:13 +00006287static MaybeObject* Runtime_Math_log(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006288 NoHandleAllocation ha;
6289 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006290 Counters::math_log.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006291
6292 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006293 return TranscendentalCache::Get(TranscendentalCache::LOG, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006294}
6295
6296
lrn@chromium.org303ada72010-10-27 09:33:13 +00006297static MaybeObject* Runtime_Math_pow(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006298 NoHandleAllocation ha;
6299 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006300 Counters::math_pow.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006301
6302 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006303
6304 // If the second argument is a smi, it is much faster to call the
6305 // custom powi() function than the generic pow().
6306 if (args[1]->IsSmi()) {
6307 int y = Smi::cast(args[1])->value();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006308 return Heap::NumberFromDouble(power_double_int(x, y));
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006309 }
6310
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006311 CONVERT_DOUBLE_CHECKED(y, args[1]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006312 return Heap::AllocateHeapNumber(power_double_double(x, y));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006313}
6314
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006315// Fast version of Math.pow if we know that y is not an integer and
6316// y is not -0.5 or 0.5. Used as slowcase from codegen.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006317static MaybeObject* Runtime_Math_pow_cfunction(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006318 NoHandleAllocation ha;
6319 ASSERT(args.length() == 2);
6320 CONVERT_DOUBLE_CHECKED(x, args[0]);
6321 CONVERT_DOUBLE_CHECKED(y, args[1]);
6322 if (y == 0) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006323 return Smi::FromInt(1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006324 } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006325 return Heap::nan_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006326 } else {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006327 return Heap::AllocateHeapNumber(pow(x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006328 }
6329}
6330
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006331
lrn@chromium.org303ada72010-10-27 09:33:13 +00006332static MaybeObject* Runtime_RoundNumber(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006333 NoHandleAllocation ha;
6334 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006335 Counters::math_round.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006336
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006337 if (!args[0]->IsHeapNumber()) {
6338 // Must be smi. Return the argument unchanged for all the other types
6339 // to make fuzz-natives test happy.
6340 return args[0];
6341 }
6342
6343 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
6344
6345 double value = number->value();
6346 int exponent = number->get_exponent();
6347 int sign = number->get_sign();
6348
6349 // We compare with kSmiValueSize - 3 because (2^30 - 0.1) has exponent 29 and
6350 // should be rounded to 2^30, which is not smi.
6351 if (!sign && exponent <= kSmiValueSize - 3) {
6352 return Smi::FromInt(static_cast<int>(value + 0.5));
6353 }
6354
6355 // If the magnitude is big enough, there's no place for fraction part. If we
6356 // try to add 0.5 to this number, 1.0 will be added instead.
6357 if (exponent >= 52) {
6358 return number;
6359 }
6360
6361 if (sign && value >= -0.5) return Heap::minus_zero_value();
6362
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006363 // Do not call NumberFromDouble() to avoid extra checks.
6364 return Heap::AllocateHeapNumber(floor(value + 0.5));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006365}
6366
6367
lrn@chromium.org303ada72010-10-27 09:33:13 +00006368static MaybeObject* Runtime_Math_sin(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006369 NoHandleAllocation ha;
6370 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006371 Counters::math_sin.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006372
6373 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006374 return TranscendentalCache::Get(TranscendentalCache::SIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006375}
6376
6377
lrn@chromium.org303ada72010-10-27 09:33:13 +00006378static MaybeObject* Runtime_Math_sqrt(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006379 NoHandleAllocation ha;
6380 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006381 Counters::math_sqrt.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006382
6383 CONVERT_DOUBLE_CHECKED(x, args[0]);
6384 return Heap::AllocateHeapNumber(sqrt(x));
6385}
6386
6387
lrn@chromium.org303ada72010-10-27 09:33:13 +00006388static MaybeObject* Runtime_Math_tan(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006389 NoHandleAllocation ha;
6390 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006391 Counters::math_tan.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006392
6393 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006394 return TranscendentalCache::Get(TranscendentalCache::TAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006395}
6396
6397
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006398static int MakeDay(int year, int month, int day) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006399 static const int day_from_month[] = {0, 31, 59, 90, 120, 151,
6400 181, 212, 243, 273, 304, 334};
6401 static const int day_from_month_leap[] = {0, 31, 60, 91, 121, 152,
6402 182, 213, 244, 274, 305, 335};
6403
6404 year += month / 12;
6405 month %= 12;
6406 if (month < 0) {
6407 year--;
6408 month += 12;
6409 }
6410
6411 ASSERT(month >= 0);
6412 ASSERT(month < 12);
6413
6414 // year_delta is an arbitrary number such that:
6415 // a) year_delta = -1 (mod 400)
6416 // b) year + year_delta > 0 for years in the range defined by
6417 // ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of
6418 // Jan 1 1970. This is required so that we don't run into integer
6419 // division of negative numbers.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006420 // c) there shouldn't be an overflow for 32-bit integers in the following
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006421 // operations.
6422 static const int year_delta = 399999;
6423 static const int base_day = 365 * (1970 + year_delta) +
6424 (1970 + year_delta) / 4 -
6425 (1970 + year_delta) / 100 +
6426 (1970 + year_delta) / 400;
6427
6428 int year1 = year + year_delta;
6429 int day_from_year = 365 * year1 +
6430 year1 / 4 -
6431 year1 / 100 +
6432 year1 / 400 -
6433 base_day;
6434
6435 if (year % 4 || (year % 100 == 0 && year % 400 != 0)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006436 return day_from_year + day_from_month[month] + day - 1;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006437 }
6438
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006439 return day_from_year + day_from_month_leap[month] + day - 1;
6440}
6441
6442
lrn@chromium.org303ada72010-10-27 09:33:13 +00006443static MaybeObject* Runtime_DateMakeDay(Arguments args) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006444 NoHandleAllocation ha;
6445 ASSERT(args.length() == 3);
6446
6447 CONVERT_SMI_CHECKED(year, args[0]);
6448 CONVERT_SMI_CHECKED(month, args[1]);
6449 CONVERT_SMI_CHECKED(date, args[2]);
6450
6451 return Smi::FromInt(MakeDay(year, month, date));
6452}
6453
6454
6455static const int kDays4Years[] = {0, 365, 2 * 365, 3 * 365 + 1};
6456static const int kDaysIn4Years = 4 * 365 + 1;
6457static const int kDaysIn100Years = 25 * kDaysIn4Years - 1;
6458static const int kDaysIn400Years = 4 * kDaysIn100Years + 1;
6459static const int kDays1970to2000 = 30 * 365 + 7;
6460static const int kDaysOffset = 1000 * kDaysIn400Years + 5 * kDaysIn400Years -
6461 kDays1970to2000;
6462static const int kYearsOffset = 400000;
6463
6464static const char kDayInYear[] = {
6465 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6466 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6467 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6468 22, 23, 24, 25, 26, 27, 28,
6469 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6470 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6471 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6472 22, 23, 24, 25, 26, 27, 28, 29, 30,
6473 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6474 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6475 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6476 22, 23, 24, 25, 26, 27, 28, 29, 30,
6477 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6478 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6479 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6480 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6481 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6482 22, 23, 24, 25, 26, 27, 28, 29, 30,
6483 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6484 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6485 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6486 22, 23, 24, 25, 26, 27, 28, 29, 30,
6487 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6488 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6489
6490 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6491 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6492 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6493 22, 23, 24, 25, 26, 27, 28,
6494 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6495 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6496 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6497 22, 23, 24, 25, 26, 27, 28, 29, 30,
6498 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6499 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6500 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6501 22, 23, 24, 25, 26, 27, 28, 29, 30,
6502 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6503 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6504 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6505 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6506 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6507 22, 23, 24, 25, 26, 27, 28, 29, 30,
6508 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6509 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6510 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6511 22, 23, 24, 25, 26, 27, 28, 29, 30,
6512 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6513 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6514
6515 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6516 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6517 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6518 22, 23, 24, 25, 26, 27, 28, 29,
6519 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6520 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6521 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6522 22, 23, 24, 25, 26, 27, 28, 29, 30,
6523 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6524 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6525 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6526 22, 23, 24, 25, 26, 27, 28, 29, 30,
6527 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6528 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6529 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6530 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6531 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6532 22, 23, 24, 25, 26, 27, 28, 29, 30,
6533 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6534 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6535 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6536 22, 23, 24, 25, 26, 27, 28, 29, 30,
6537 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6538 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6539
6540 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6541 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6542 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6543 22, 23, 24, 25, 26, 27, 28,
6544 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6545 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6546 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6547 22, 23, 24, 25, 26, 27, 28, 29, 30,
6548 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6549 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6550 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6551 22, 23, 24, 25, 26, 27, 28, 29, 30,
6552 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6553 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6554 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6555 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6556 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6557 22, 23, 24, 25, 26, 27, 28, 29, 30,
6558 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6559 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6560 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6561 22, 23, 24, 25, 26, 27, 28, 29, 30,
6562 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6563 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
6564
6565static const char kMonthInYear[] = {
6566 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,
6567 0, 0, 0, 0, 0, 0,
6568 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,
6569 1, 1, 1,
6570 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,
6571 2, 2, 2, 2, 2, 2,
6572 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,
6573 3, 3, 3, 3, 3,
6574 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,
6575 4, 4, 4, 4, 4, 4,
6576 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,
6577 5, 5, 5, 5, 5,
6578 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,
6579 6, 6, 6, 6, 6, 6,
6580 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,
6581 7, 7, 7, 7, 7, 7,
6582 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,
6583 8, 8, 8, 8, 8,
6584 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,
6585 9, 9, 9, 9, 9, 9,
6586 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6587 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6588 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6589 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6590
6591 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,
6592 0, 0, 0, 0, 0, 0,
6593 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,
6594 1, 1, 1,
6595 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,
6596 2, 2, 2, 2, 2, 2,
6597 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,
6598 3, 3, 3, 3, 3,
6599 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,
6600 4, 4, 4, 4, 4, 4,
6601 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,
6602 5, 5, 5, 5, 5,
6603 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,
6604 6, 6, 6, 6, 6, 6,
6605 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,
6606 7, 7, 7, 7, 7, 7,
6607 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,
6608 8, 8, 8, 8, 8,
6609 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,
6610 9, 9, 9, 9, 9, 9,
6611 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6612 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6613 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6614 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6615
6616 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,
6617 0, 0, 0, 0, 0, 0,
6618 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,
6619 1, 1, 1, 1,
6620 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,
6621 2, 2, 2, 2, 2, 2,
6622 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,
6623 3, 3, 3, 3, 3,
6624 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,
6625 4, 4, 4, 4, 4, 4,
6626 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,
6627 5, 5, 5, 5, 5,
6628 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,
6629 6, 6, 6, 6, 6, 6,
6630 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,
6631 7, 7, 7, 7, 7, 7,
6632 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,
6633 8, 8, 8, 8, 8,
6634 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,
6635 9, 9, 9, 9, 9, 9,
6636 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6637 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6638 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6639 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6640
6641 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,
6642 0, 0, 0, 0, 0, 0,
6643 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,
6644 1, 1, 1,
6645 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,
6646 2, 2, 2, 2, 2, 2,
6647 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,
6648 3, 3, 3, 3, 3,
6649 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,
6650 4, 4, 4, 4, 4, 4,
6651 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,
6652 5, 5, 5, 5, 5,
6653 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,
6654 6, 6, 6, 6, 6, 6,
6655 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,
6656 7, 7, 7, 7, 7, 7,
6657 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,
6658 8, 8, 8, 8, 8,
6659 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,
6660 9, 9, 9, 9, 9, 9,
6661 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6662 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6663 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6664 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11};
6665
6666
6667// This function works for dates from 1970 to 2099.
6668static inline void DateYMDFromTimeAfter1970(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006669 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006670#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00006671 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006672#endif
6673
6674 year = 1970 + (4 * date + 2) / kDaysIn4Years;
6675 date %= kDaysIn4Years;
6676
6677 month = kMonthInYear[date];
6678 day = kDayInYear[date];
6679
6680 ASSERT(MakeDay(year, month, day) == save_date);
6681}
6682
6683
6684static inline void DateYMDFromTimeSlow(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006685 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006686#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00006687 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006688#endif
6689
6690 date += kDaysOffset;
6691 year = 400 * (date / kDaysIn400Years) - kYearsOffset;
6692 date %= kDaysIn400Years;
6693
6694 ASSERT(MakeDay(year, 0, 1) + date == save_date);
6695
6696 date--;
6697 int yd1 = date / kDaysIn100Years;
6698 date %= kDaysIn100Years;
6699 year += 100 * yd1;
6700
6701 date++;
6702 int yd2 = date / kDaysIn4Years;
6703 date %= kDaysIn4Years;
6704 year += 4 * yd2;
6705
6706 date--;
6707 int yd3 = date / 365;
6708 date %= 365;
6709 year += yd3;
6710
6711 bool is_leap = (!yd1 || yd2) && !yd3;
6712
6713 ASSERT(date >= -1);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006714 ASSERT(is_leap || (date >= 0));
6715 ASSERT((date < 365) || (is_leap && (date < 366)));
6716 ASSERT(is_leap == ((year % 4 == 0) && (year % 100 || (year % 400 == 0))));
6717 ASSERT(is_leap || ((MakeDay(year, 0, 1) + date) == save_date));
6718 ASSERT(!is_leap || ((MakeDay(year, 0, 1) + date + 1) == save_date));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006719
6720 if (is_leap) {
6721 day = kDayInYear[2*365 + 1 + date];
6722 month = kMonthInYear[2*365 + 1 + date];
6723 } else {
6724 day = kDayInYear[date];
6725 month = kMonthInYear[date];
6726 }
6727
6728 ASSERT(MakeDay(year, month, day) == save_date);
6729}
6730
6731
6732static inline void DateYMDFromTime(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006733 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006734 if (date >= 0 && date < 32 * kDaysIn4Years) {
6735 DateYMDFromTimeAfter1970(date, year, month, day);
6736 } else {
6737 DateYMDFromTimeSlow(date, year, month, day);
6738 }
6739}
6740
6741
lrn@chromium.org303ada72010-10-27 09:33:13 +00006742static MaybeObject* Runtime_DateYMDFromTime(Arguments args) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006743 NoHandleAllocation ha;
6744 ASSERT(args.length() == 2);
6745
6746 CONVERT_DOUBLE_CHECKED(t, args[0]);
6747 CONVERT_CHECKED(JSArray, res_array, args[1]);
6748
6749 int year, month, day;
6750 DateYMDFromTime(static_cast<int>(floor(t / 86400000)), year, month, day);
6751
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00006752 RUNTIME_ASSERT(res_array->elements()->map() == Heap::fixed_array_map());
6753 FixedArray* elms = FixedArray::cast(res_array->elements());
6754 RUNTIME_ASSERT(elms->length() == 3);
6755
6756 elms->set(0, Smi::FromInt(year));
6757 elms->set(1, Smi::FromInt(month));
6758 elms->set(2, Smi::FromInt(day));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006759
6760 return Heap::undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006761}
6762
6763
lrn@chromium.org303ada72010-10-27 09:33:13 +00006764static MaybeObject* Runtime_NewArgumentsFast(Arguments args) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00006765 NoHandleAllocation ha;
6766 ASSERT(args.length() == 3);
6767
6768 JSFunction* callee = JSFunction::cast(args[0]);
6769 Object** parameters = reinterpret_cast<Object**>(args[1]);
6770 const int length = Smi::cast(args[2])->value();
6771
lrn@chromium.org303ada72010-10-27 09:33:13 +00006772 Object* result;
6773 { MaybeObject* maybe_result = Heap::AllocateArgumentsObject(callee, length);
6774 if (!maybe_result->ToObject(&result)) return maybe_result;
6775 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006776 // Allocate the elements if needed.
6777 if (length > 0) {
6778 // Allocate the fixed array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006779 Object* obj;
6780 { MaybeObject* maybe_obj = Heap::AllocateRawFixedArray(length);
6781 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6782 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006783
6784 AssertNoAllocation no_gc;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006785 FixedArray* array = reinterpret_cast<FixedArray*>(obj);
6786 array->set_map(Heap::fixed_array_map());
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006787 array->set_length(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006788
6789 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006790 for (int i = 0; i < length; i++) {
6791 array->set(i, *--parameters, mode);
6792 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006793 JSObject::cast(result)->set_elements(FixedArray::cast(obj));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00006794 }
6795 return result;
6796}
6797
6798
lrn@chromium.org303ada72010-10-27 09:33:13 +00006799static MaybeObject* Runtime_NewClosure(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006800 HandleScope scope;
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00006801 ASSERT(args.length() == 3);
ager@chromium.org3811b432009-10-28 14:53:37 +00006802 CONVERT_ARG_CHECKED(Context, context, 0);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00006803 CONVERT_ARG_CHECKED(SharedFunctionInfo, shared, 1);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00006804 CONVERT_BOOLEAN_CHECKED(pretenure, args[2]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006805
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00006806 // Allocate global closures in old space and allocate local closures
6807 // in new space. Additionally pretenure closures that are assigned
6808 // directly to properties.
6809 pretenure = pretenure || (context->global_context() == *context);
6810 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006811 Handle<JSFunction> result =
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00006812 Factory::NewFunctionFromSharedFunctionInfo(shared,
6813 context,
6814 pretenure_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006815 return *result;
6816}
6817
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00006818
lrn@chromium.org303ada72010-10-27 09:33:13 +00006819static MaybeObject* Runtime_NewObjectFromBound(Arguments args) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006820 HandleScope scope;
6821 ASSERT(args.length() == 2);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00006822 // First argument is a function to use as a constructor.
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006823 CONVERT_ARG_CHECKED(JSFunction, function, 0);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006824
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00006825 // Second argument is either null or an array of bound arguments.
6826 FixedArray* bound_args = NULL;
6827 int bound_argc = 0;
6828 if (!args[1]->IsNull()) {
6829 CONVERT_ARG_CHECKED(JSArray, params, 1);
6830 RUNTIME_ASSERT(params->HasFastElements());
6831 bound_args = FixedArray::cast(params->elements());
6832 bound_argc = Smi::cast(params->length())->value();
6833 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006834
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00006835 // Find frame containing arguments passed to the caller.
6836 JavaScriptFrameIterator it;
6837 JavaScriptFrame* frame = it.frame();
6838 ASSERT(!frame->is_optimized());
6839 it.AdvanceToArgumentsFrame();
6840 frame = it.frame();
6841 int argc = frame->GetProvidedParametersCount();
6842
6843 // Prepend bound arguments to caller's arguments.
6844 int total_argc = bound_argc + argc;
6845 SmartPointer<Object**> param_data(NewArray<Object**>(total_argc));
6846 for (int i = 0; i < bound_argc; i++) {
6847 Handle<Object> val = Handle<Object>(bound_args->get(i));
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006848 param_data[i] = val.location();
6849 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00006850 for (int i = 0; i < argc; i++) {
6851 Handle<Object> val = Handle<Object>(frame->GetParameter(i));
6852 param_data[bound_argc + i] = val.location();
6853 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006854
whesse@chromium.orge90029b2010-08-02 11:52:17 +00006855 bool exception = false;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00006856 Handle<Object> result =
6857 Execution::New(function, total_argc, *param_data, &exception);
whesse@chromium.orge90029b2010-08-02 11:52:17 +00006858 if (exception) {
6859 return Failure::Exception();
6860 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00006861
whesse@chromium.orge90029b2010-08-02 11:52:17 +00006862 ASSERT(!result.is_null());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006863 return *result;
6864}
6865
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006866
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006867static void TrySettingInlineConstructStub(Handle<JSFunction> function) {
ager@chromium.org5c838252010-02-19 08:53:10 +00006868 Handle<Object> prototype = Factory::null_value();
6869 if (function->has_instance_prototype()) {
6870 prototype = Handle<Object>(function->instance_prototype());
6871 }
6872 if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006873 ConstructStubCompiler compiler;
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006874 MaybeObject* code = compiler.CompileConstructStub(*function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006875 if (!code->IsFailure()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00006876 function->shared()->set_construct_stub(
6877 Code::cast(code->ToObjectUnchecked()));
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006878 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006879 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006880}
6881
6882
lrn@chromium.org303ada72010-10-27 09:33:13 +00006883static MaybeObject* Runtime_NewObject(Arguments args) {
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006884 HandleScope scope;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006885 ASSERT(args.length() == 1);
6886
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006887 Handle<Object> constructor = args.at<Object>(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006888
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006889 // If the constructor isn't a proper function we throw a type error.
6890 if (!constructor->IsJSFunction()) {
6891 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
6892 Handle<Object> type_error =
6893 Factory::NewTypeError("not_constructor", arguments);
6894 return Top::Throw(*type_error);
6895 }
6896
6897 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006898
6899 // If function should not have prototype, construction is not allowed. In this
6900 // case generated code bailouts here, since function has no initial_map.
6901 if (!function->should_have_prototype()) {
6902 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
6903 Handle<Object> type_error =
6904 Factory::NewTypeError("not_constructor", arguments);
6905 return Top::Throw(*type_error);
6906 }
6907
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006908#ifdef ENABLE_DEBUGGER_SUPPORT
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006909 // Handle stepping into constructors if step into is active.
6910 if (Debug::StepInActive()) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006911 Debug::HandleStepIn(function, Handle<Object>::null(), 0, true);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006912 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006913#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006914
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006915 if (function->has_initial_map()) {
6916 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006917 // The 'Function' function ignores the receiver object when
6918 // called using 'new' and creates a new JSFunction object that
6919 // is returned. The receiver object is only used for error
6920 // reporting if an error occurs when constructing the new
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006921 // JSFunction. Factory::NewJSObject() should not be used to
6922 // allocate JSFunctions since it does not properly initialize
6923 // the shared part of the function. Since the receiver is
6924 // ignored anyway, we use the global object as the receiver
6925 // instead of a new JSFunction object. This way, errors are
6926 // reported the same way whether or not 'Function' is called
6927 // using 'new'.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006928 return Top::context()->global();
6929 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006930 }
6931
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006932 // The function should be compiled for the optimization hints to be
6933 // available. We cannot use EnsureCompiled because that forces a
6934 // compilation through the shared function info which makes it
6935 // impossible for us to optimize.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006936 Handle<SharedFunctionInfo> shared(function->shared());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006937 if (!function->is_compiled()) CompileLazy(function, CLEAR_EXCEPTION);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006938
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006939 if (!function->has_initial_map() &&
6940 shared->IsInobjectSlackTrackingInProgress()) {
6941 // The tracking is already in progress for another function. We can only
6942 // track one initial_map at a time, so we force the completion before the
6943 // function is called as a constructor for the first time.
6944 shared->CompleteInobjectSlackTracking();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006945 }
6946
6947 bool first_allocation = !shared->live_objects_may_exist();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006948 Handle<JSObject> result = Factory::NewJSObject(function);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006949 RETURN_IF_EMPTY_HANDLE(result);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006950 // Delay setting the stub if inobject slack tracking is in progress.
6951 if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) {
6952 TrySettingInlineConstructStub(function);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006953 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006954
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00006955 Counters::constructed_objects.Increment();
6956 Counters::constructed_objects_runtime.Increment();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006957
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006958 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006959}
6960
6961
lrn@chromium.org303ada72010-10-27 09:33:13 +00006962static MaybeObject* Runtime_FinalizeInstanceSize(Arguments args) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006963 HandleScope scope;
6964 ASSERT(args.length() == 1);
6965
6966 CONVERT_ARG_CHECKED(JSFunction, function, 0);
6967 function->shared()->CompleteInobjectSlackTracking();
6968 TrySettingInlineConstructStub(function);
6969
6970 return Heap::undefined_value();
6971}
6972
6973
lrn@chromium.org303ada72010-10-27 09:33:13 +00006974static MaybeObject* Runtime_LazyCompile(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006975 HandleScope scope;
6976 ASSERT(args.length() == 1);
6977
6978 Handle<JSFunction> function = args.at<JSFunction>(0);
6979#ifdef DEBUG
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00006980 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006981 PrintF("[lazy: ");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006982 function->PrintName();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006983 PrintF("]\n");
6984 }
6985#endif
6986
kasperl@chromium.org71affb52009-05-26 05:44:31 +00006987 // Compile the target function. Here we compile using CompileLazyInLoop in
6988 // order to get the optimized version. This helps code like delta-blue
6989 // that calls performance-critical routines through constructors. A
6990 // constructor call doesn't use a CallIC, it uses a LoadIC followed by a
6991 // direct call. Since the in-loop tracking takes place through CallICs
6992 // this means that things called through constructors are never known to
6993 // be in loops. We compile them as if they are in loops here just in case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006994 ASSERT(!function->is_compiled());
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00006995 if (!CompileLazyInLoop(function, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006996 return Failure::Exception();
6997 }
6998
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006999 // All done. Return the compiled code.
7000 ASSERT(function->is_compiled());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007001 return function->code();
7002}
7003
7004
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007005static MaybeObject* Runtime_LazyRecompile(Arguments args) {
7006 HandleScope scope;
7007 ASSERT(args.length() == 1);
7008 Handle<JSFunction> function = args.at<JSFunction>(0);
7009 // If the function is not optimizable or debugger is active continue using the
7010 // code from the full compiler.
7011 if (!function->shared()->code()->optimizable() ||
7012 Debug::has_break_points()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007013 if (FLAG_trace_opt) {
7014 PrintF("[failed to optimize ");
7015 function->PrintName();
7016 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n",
7017 function->shared()->code()->optimizable() ? "T" : "F",
7018 Debug::has_break_points() ? "T" : "F");
7019 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007020 function->ReplaceCode(function->shared()->code());
7021 return function->code();
7022 }
7023 if (CompileOptimized(function, AstNode::kNoNumber)) {
7024 return function->code();
7025 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007026 if (FLAG_trace_opt) {
7027 PrintF("[failed to optimize ");
7028 function->PrintName();
7029 PrintF(": optimized compilation failed]\n");
7030 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007031 function->ReplaceCode(function->shared()->code());
7032 return Failure::Exception();
7033}
7034
7035
7036static MaybeObject* Runtime_NotifyDeoptimized(Arguments args) {
7037 HandleScope scope;
7038 ASSERT(args.length() == 1);
7039 RUNTIME_ASSERT(args[0]->IsSmi());
7040 Deoptimizer::BailoutType type =
7041 static_cast<Deoptimizer::BailoutType>(Smi::cast(args[0])->value());
7042 Deoptimizer* deoptimizer = Deoptimizer::Grab();
7043 ASSERT(Heap::IsAllocationAllowed());
7044 int frames = deoptimizer->output_count();
7045
7046 JavaScriptFrameIterator it;
7047 JavaScriptFrame* frame = NULL;
7048 for (int i = 0; i < frames; i++) {
7049 if (i != 0) it.Advance();
7050 frame = it.frame();
7051 deoptimizer->InsertHeapNumberValues(frames - i - 1, frame);
7052 }
7053 delete deoptimizer;
7054
7055 RUNTIME_ASSERT(frame->function()->IsJSFunction());
7056 Handle<JSFunction> function(JSFunction::cast(frame->function()));
7057 Handle<Object> arguments;
7058 for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00007059 if (frame->GetExpression(i) == Heap::arguments_marker()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007060 if (arguments.is_null()) {
7061 // FunctionGetArguments can't throw an exception, so cast away the
7062 // doubt with an assert.
7063 arguments = Handle<Object>(
7064 Accessors::FunctionGetArguments(*function,
7065 NULL)->ToObjectUnchecked());
7066 ASSERT(*arguments != Heap::null_value());
7067 ASSERT(*arguments != Heap::undefined_value());
7068 }
7069 frame->SetExpression(i, *arguments);
7070 }
7071 }
7072
7073 CompilationCache::MarkForLazyOptimizing(function);
7074 if (type == Deoptimizer::EAGER) {
7075 RUNTIME_ASSERT(function->IsOptimized());
7076 } else {
7077 RUNTIME_ASSERT(!function->IsOptimized());
7078 }
7079
7080 // Avoid doing too much work when running with --always-opt and keep
7081 // the optimized code around.
7082 if (FLAG_always_opt || type == Deoptimizer::LAZY) {
7083 return Heap::undefined_value();
7084 }
7085
7086 // Count the number of optimized activations of the function.
7087 int activations = 0;
7088 while (!it.done()) {
7089 JavaScriptFrame* frame = it.frame();
7090 if (frame->is_optimized() && frame->function() == *function) {
7091 activations++;
7092 }
7093 it.Advance();
7094 }
7095
7096 // TODO(kasperl): For now, we cannot support removing the optimized
7097 // code when we have recursive invocations of the same function.
7098 if (activations == 0) {
7099 if (FLAG_trace_deopt) {
7100 PrintF("[removing optimized code for: ");
7101 function->PrintName();
7102 PrintF("]\n");
7103 }
7104 function->ReplaceCode(function->shared()->code());
7105 }
7106 return Heap::undefined_value();
7107}
7108
7109
7110static MaybeObject* Runtime_NotifyOSR(Arguments args) {
7111 Deoptimizer* deoptimizer = Deoptimizer::Grab();
7112 delete deoptimizer;
7113 return Heap::undefined_value();
7114}
7115
7116
7117static MaybeObject* Runtime_DeoptimizeFunction(Arguments args) {
7118 HandleScope scope;
7119 ASSERT(args.length() == 1);
7120 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7121 if (!function->IsOptimized()) return Heap::undefined_value();
7122
7123 Deoptimizer::DeoptimizeFunction(*function);
7124
7125 return Heap::undefined_value();
7126}
7127
7128
7129static MaybeObject* Runtime_CompileForOnStackReplacement(Arguments args) {
7130 HandleScope scope;
7131 ASSERT(args.length() == 1);
7132 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7133
7134 // We're not prepared to handle a function with arguments object.
7135 ASSERT(!function->shared()->scope_info()->HasArgumentsShadow());
7136
7137 // We have hit a back edge in an unoptimized frame for a function that was
7138 // selected for on-stack replacement. Find the unoptimized code object.
7139 Handle<Code> unoptimized(function->shared()->code());
7140 // Keep track of whether we've succeeded in optimizing.
7141 bool succeeded = unoptimized->optimizable();
7142 if (succeeded) {
7143 // If we are trying to do OSR when there are already optimized
7144 // activations of the function, it means (a) the function is directly or
7145 // indirectly recursive and (b) an optimized invocation has been
7146 // deoptimized so that we are currently in an unoptimized activation.
7147 // Check for optimized activations of this function.
7148 JavaScriptFrameIterator it;
7149 while (succeeded && !it.done()) {
7150 JavaScriptFrame* frame = it.frame();
7151 succeeded = !frame->is_optimized() || frame->function() != *function;
7152 it.Advance();
7153 }
7154 }
7155
7156 int ast_id = AstNode::kNoNumber;
7157 if (succeeded) {
7158 // The top JS function is this one, the PC is somewhere in the
7159 // unoptimized code.
7160 JavaScriptFrameIterator it;
7161 JavaScriptFrame* frame = it.frame();
7162 ASSERT(frame->function() == *function);
7163 ASSERT(frame->code() == *unoptimized);
7164 ASSERT(unoptimized->contains(frame->pc()));
7165
7166 // Use linear search of the unoptimized code's stack check table to find
7167 // the AST id matching the PC.
7168 Address start = unoptimized->instruction_start();
7169 unsigned target_pc_offset = static_cast<unsigned>(frame->pc() - start);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007170 Address table_cursor = start + unoptimized->stack_check_table_offset();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007171 uint32_t table_length = Memory::uint32_at(table_cursor);
7172 table_cursor += kIntSize;
7173 for (unsigned i = 0; i < table_length; ++i) {
7174 // Table entries are (AST id, pc offset) pairs.
7175 uint32_t pc_offset = Memory::uint32_at(table_cursor + kIntSize);
7176 if (pc_offset == target_pc_offset) {
7177 ast_id = static_cast<int>(Memory::uint32_at(table_cursor));
7178 break;
7179 }
7180 table_cursor += 2 * kIntSize;
7181 }
7182 ASSERT(ast_id != AstNode::kNoNumber);
7183 if (FLAG_trace_osr) {
7184 PrintF("[replacing on-stack at AST id %d in ", ast_id);
7185 function->PrintName();
7186 PrintF("]\n");
7187 }
7188
7189 // Try to compile the optimized code. A true return value from
7190 // CompileOptimized means that compilation succeeded, not necessarily
7191 // that optimization succeeded.
7192 if (CompileOptimized(function, ast_id) && function->IsOptimized()) {
7193 DeoptimizationInputData* data = DeoptimizationInputData::cast(
7194 function->code()->deoptimization_data());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007195 if (data->OsrPcOffset()->value() >= 0) {
7196 if (FLAG_trace_osr) {
7197 PrintF("[on-stack replacement offset %d in optimized code]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007198 data->OsrPcOffset()->value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007199 }
7200 ASSERT(data->OsrAstId()->value() == ast_id);
7201 } else {
7202 // We may never generate the desired OSR entry if we emit an
7203 // early deoptimize.
7204 succeeded = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007205 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007206 } else {
7207 succeeded = false;
7208 }
7209 }
7210
7211 // Revert to the original stack checks in the original unoptimized code.
7212 if (FLAG_trace_osr) {
7213 PrintF("[restoring original stack checks in ");
7214 function->PrintName();
7215 PrintF("]\n");
7216 }
7217 StackCheckStub check_stub;
7218 Handle<Code> check_code = check_stub.GetCode();
7219 Handle<Code> replacement_code(
7220 Builtins::builtin(Builtins::OnStackReplacement));
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007221 Deoptimizer::RevertStackCheckCode(*unoptimized,
7222 *check_code,
7223 *replacement_code);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007224
7225 // Allow OSR only at nesting level zero again.
7226 unoptimized->set_allow_osr_at_loop_nesting_level(0);
7227
7228 // If the optimization attempt succeeded, return the AST id tagged as a
7229 // smi. This tells the builtin that we need to translate the unoptimized
7230 // frame to an optimized one.
7231 if (succeeded) {
7232 ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
7233 return Smi::FromInt(ast_id);
7234 } else {
7235 return Smi::FromInt(-1);
7236 }
7237}
7238
7239
lrn@chromium.org303ada72010-10-27 09:33:13 +00007240static MaybeObject* Runtime_GetFunctionDelegate(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007241 HandleScope scope;
7242 ASSERT(args.length() == 1);
7243 RUNTIME_ASSERT(!args[0]->IsJSFunction());
7244 return *Execution::GetFunctionDelegate(args.at<Object>(0));
7245}
7246
7247
lrn@chromium.org303ada72010-10-27 09:33:13 +00007248static MaybeObject* Runtime_GetConstructorDelegate(Arguments args) {
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00007249 HandleScope scope;
7250 ASSERT(args.length() == 1);
7251 RUNTIME_ASSERT(!args[0]->IsJSFunction());
7252 return *Execution::GetConstructorDelegate(args.at<Object>(0));
7253}
7254
7255
lrn@chromium.org303ada72010-10-27 09:33:13 +00007256static MaybeObject* Runtime_NewContext(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007257 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00007258 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007259
kasper.lund7276f142008-07-30 08:49:36 +00007260 CONVERT_CHECKED(JSFunction, function, args[0]);
ager@chromium.orgb5737492010-07-15 09:29:43 +00007261 int length = function->shared()->scope_info()->NumberOfContextSlots();
lrn@chromium.org303ada72010-10-27 09:33:13 +00007262 Object* result;
7263 { MaybeObject* maybe_result = Heap::AllocateFunctionContext(length, function);
7264 if (!maybe_result->ToObject(&result)) return maybe_result;
7265 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007266
7267 Top::set_context(Context::cast(result));
7268
kasper.lund7276f142008-07-30 08:49:36 +00007269 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007270}
7271
lrn@chromium.org303ada72010-10-27 09:33:13 +00007272
7273MUST_USE_RESULT static MaybeObject* PushContextHelper(Object* object,
7274 bool is_catch_context) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007275 // Convert the object to a proper JavaScript object.
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007276 Object* js_object = object;
7277 if (!js_object->IsJSObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007278 MaybeObject* maybe_js_object = js_object->ToObject();
7279 if (!maybe_js_object->ToObject(&js_object)) {
7280 if (!Failure::cast(maybe_js_object)->IsInternalError()) {
7281 return maybe_js_object;
7282 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007283 HandleScope scope;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007284 Handle<Object> handle(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007285 Handle<Object> result =
7286 Factory::NewTypeError("with_expression", HandleVector(&handle, 1));
7287 return Top::Throw(*result);
7288 }
7289 }
7290
lrn@chromium.org303ada72010-10-27 09:33:13 +00007291 Object* result;
7292 { MaybeObject* maybe_result =
7293 Heap::AllocateWithContext(Top::context(),
7294 JSObject::cast(js_object),
7295 is_catch_context);
7296 if (!maybe_result->ToObject(&result)) return maybe_result;
7297 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007298
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007299 Context* context = Context::cast(result);
7300 Top::set_context(context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007301
kasper.lund7276f142008-07-30 08:49:36 +00007302 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007303}
7304
7305
lrn@chromium.org303ada72010-10-27 09:33:13 +00007306static MaybeObject* Runtime_PushContext(Arguments args) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007307 NoHandleAllocation ha;
7308 ASSERT(args.length() == 1);
7309 return PushContextHelper(args[0], false);
7310}
7311
7312
lrn@chromium.org303ada72010-10-27 09:33:13 +00007313static MaybeObject* Runtime_PushCatchContext(Arguments args) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007314 NoHandleAllocation ha;
7315 ASSERT(args.length() == 1);
7316 return PushContextHelper(args[0], true);
7317}
7318
7319
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007320static MaybeObject* Runtime_DeleteContextSlot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007321 HandleScope scope;
7322 ASSERT(args.length() == 2);
7323
7324 CONVERT_ARG_CHECKED(Context, context, 0);
7325 CONVERT_ARG_CHECKED(String, name, 1);
7326
7327 int index;
7328 PropertyAttributes attributes;
7329 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007330 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007331
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007332 // If the slot was not found the result is true.
7333 if (holder.is_null()) {
7334 return Heap::true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007335 }
7336
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007337 // If the slot was found in a context, it should be DONT_DELETE.
7338 if (holder->IsContext()) {
7339 return Heap::false_value();
7340 }
7341
7342 // The slot was found in a JSObject, either a context extension object,
7343 // the global object, or an arguments object. Try to delete it
7344 // (respecting DONT_DELETE). For consistency with V8's usual behavior,
7345 // which allows deleting all parameters in functions that mention
7346 // 'arguments', we do this even for the case of slots found on an
7347 // arguments object. The slot was found on an arguments object if the
7348 // index is non-negative.
7349 Handle<JSObject> object = Handle<JSObject>::cast(holder);
7350 if (index >= 0) {
7351 return object->DeleteElement(index, JSObject::NORMAL_DELETION);
7352 } else {
7353 return object->DeleteProperty(*name, JSObject::NORMAL_DELETION);
7354 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007355}
7356
7357
ager@chromium.orga1645e22009-09-09 19:27:10 +00007358// A mechanism to return a pair of Object pointers in registers (if possible).
7359// How this is achieved is calling convention-dependent.
7360// All currently supported x86 compiles uses calling conventions that are cdecl
7361// variants where a 64-bit value is returned in two 32-bit registers
7362// (edx:eax on ia32, r1:r0 on ARM).
7363// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
7364// In Win64 calling convention, a struct of two pointers is returned in memory,
7365// allocated by the caller, and passed as a pointer in a hidden first parameter.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007366#ifdef V8_HOST_ARCH_64_BIT
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007367struct ObjectPair {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007368 MaybeObject* x;
7369 MaybeObject* y;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007370};
ager@chromium.orga1645e22009-09-09 19:27:10 +00007371
lrn@chromium.org303ada72010-10-27 09:33:13 +00007372static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007373 ObjectPair result = {x, y};
ager@chromium.orga1645e22009-09-09 19:27:10 +00007374 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
7375 // In Win64 they are assigned to a hidden first argument.
7376 return result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007377}
7378#else
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007379typedef uint64_t ObjectPair;
lrn@chromium.org303ada72010-10-27 09:33:13 +00007380static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007381 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007382 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007383}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007384#endif
7385
7386
lrn@chromium.org303ada72010-10-27 09:33:13 +00007387static inline MaybeObject* Unhole(MaybeObject* x,
7388 PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007389 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
7390 USE(attributes);
7391 return x->IsTheHole() ? Heap::undefined_value() : x;
7392}
7393
7394
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007395static JSObject* ComputeReceiverForNonGlobal(JSObject* holder) {
7396 ASSERT(!holder->IsGlobalObject());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007397 Context* top = Top::context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007398 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007399 JSFunction* context_extension_function =
7400 top->global_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007401 // If the holder isn't a context extension object, we just return it
7402 // as the receiver. This allows arguments objects to be used as
7403 // receivers, but only if they are put in the context scope chain
7404 // explicitly via a with-statement.
7405 Object* constructor = holder->map()->constructor();
7406 if (constructor != context_extension_function) return holder;
7407 // Fall back to using the global object as the receiver if the
7408 // property turns out to be a local variable allocated in a context
7409 // extension object - introduced via eval.
7410 return top->global()->global_receiver();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007411}
7412
7413
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007414static ObjectPair LoadContextSlotHelper(Arguments args, bool throw_error) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007415 HandleScope scope;
ager@chromium.orga1645e22009-09-09 19:27:10 +00007416 ASSERT_EQ(2, args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007417
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007418 if (!args[0]->IsContext() || !args[1]->IsString()) {
ager@chromium.org3e875802009-06-29 08:26:34 +00007419 return MakePair(Top::ThrowIllegalOperation(), NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007420 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007421 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007422 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007423
7424 int index;
7425 PropertyAttributes attributes;
7426 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007427 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007428
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007429 // If the index is non-negative, the slot has been found in a local
7430 // variable or a parameter. Read it from the context object or the
7431 // arguments object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007432 if (index >= 0) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007433 // If the "property" we were looking for is a local variable or an
7434 // argument in a context, the receiver is the global object; see
7435 // ECMA-262, 3rd., 10.1.6 and 10.2.3.
7436 JSObject* receiver = Top::context()->global()->global_receiver();
lrn@chromium.org303ada72010-10-27 09:33:13 +00007437 MaybeObject* value = (holder->IsContext())
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007438 ? Context::cast(*holder)->get(index)
7439 : JSObject::cast(*holder)->GetElement(index);
7440 return MakePair(Unhole(value, attributes), receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007441 }
7442
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007443 // If the holder is found, we read the property from it.
7444 if (!holder.is_null() && holder->IsJSObject()) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007445 ASSERT(Handle<JSObject>::cast(holder)->HasProperty(*name));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007446 JSObject* object = JSObject::cast(*holder);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007447 JSObject* receiver;
7448 if (object->IsGlobalObject()) {
7449 receiver = GlobalObject::cast(object)->global_receiver();
7450 } else if (context->is_exception_holder(*holder)) {
7451 receiver = Top::context()->global()->global_receiver();
7452 } else {
7453 receiver = ComputeReceiverForNonGlobal(object);
7454 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007455 // No need to unhole the value here. This is taken care of by the
7456 // GetProperty function.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007457 MaybeObject* value = object->GetProperty(*name);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007458 return MakePair(value, receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007459 }
7460
7461 if (throw_error) {
7462 // The property doesn't exist - throw exception.
7463 Handle<Object> reference_error =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007464 Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007465 return MakePair(Top::Throw(*reference_error), NULL);
7466 } else {
7467 // The property doesn't exist - return undefined
7468 return MakePair(Heap::undefined_value(), Heap::undefined_value());
7469 }
7470}
7471
7472
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007473static ObjectPair Runtime_LoadContextSlot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007474 return LoadContextSlotHelper(args, true);
7475}
7476
7477
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007478static ObjectPair Runtime_LoadContextSlotNoReferenceError(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007479 return LoadContextSlotHelper(args, false);
7480}
7481
7482
lrn@chromium.org303ada72010-10-27 09:33:13 +00007483static MaybeObject* Runtime_StoreContextSlot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007484 HandleScope scope;
7485 ASSERT(args.length() == 3);
7486
7487 Handle<Object> value(args[0]);
7488 CONVERT_ARG_CHECKED(Context, context, 1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007489 CONVERT_ARG_CHECKED(String, name, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007490
7491 int index;
7492 PropertyAttributes attributes;
7493 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007494 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007495
7496 if (index >= 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007497 if (holder->IsContext()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007498 // Ignore if read_only variable.
7499 if ((attributes & READ_ONLY) == 0) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007500 // Context is a fixed array and set cannot fail.
7501 Context::cast(*holder)->set(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007502 }
7503 } else {
7504 ASSERT((attributes & READ_ONLY) == 0);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007505 Handle<Object> result =
7506 SetElement(Handle<JSObject>::cast(holder), index, value);
7507 if (result.is_null()) {
7508 ASSERT(Top::has_pending_exception());
7509 return Failure::Exception();
7510 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007511 }
7512 return *value;
7513 }
7514
7515 // Slow case: The property is not in a FixedArray context.
7516 // It is either in an JSObject extension context or it was not found.
7517 Handle<JSObject> context_ext;
7518
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007519 if (!holder.is_null()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007520 // The property exists in the extension context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007521 context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007522 } else {
7523 // The property was not found. It needs to be stored in the global context.
7524 ASSERT(attributes == ABSENT);
7525 attributes = NONE;
7526 context_ext = Handle<JSObject>(Top::context()->global());
7527 }
7528
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007529 // Set the property, but ignore if read_only variable on the context
7530 // extension object itself.
7531 if ((attributes & READ_ONLY) == 0 ||
7532 (context_ext->GetLocalPropertyAttribute(*name) == ABSENT)) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00007533 RETURN_IF_EMPTY_HANDLE(SetProperty(context_ext, name, value, NONE));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007534 }
7535 return *value;
7536}
7537
7538
lrn@chromium.org303ada72010-10-27 09:33:13 +00007539static MaybeObject* Runtime_Throw(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007540 HandleScope scope;
7541 ASSERT(args.length() == 1);
7542
7543 return Top::Throw(args[0]);
7544}
7545
7546
lrn@chromium.org303ada72010-10-27 09:33:13 +00007547static MaybeObject* Runtime_ReThrow(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007548 HandleScope scope;
7549 ASSERT(args.length() == 1);
7550
7551 return Top::ReThrow(args[0]);
7552}
7553
7554
lrn@chromium.org303ada72010-10-27 09:33:13 +00007555static MaybeObject* Runtime_PromoteScheduledException(Arguments args) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007556 ASSERT_EQ(0, args.length());
7557 return Top::PromoteScheduledException();
7558}
7559
7560
lrn@chromium.org303ada72010-10-27 09:33:13 +00007561static MaybeObject* Runtime_ThrowReferenceError(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007562 HandleScope scope;
7563 ASSERT(args.length() == 1);
7564
7565 Handle<Object> name(args[0]);
7566 Handle<Object> reference_error =
7567 Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
7568 return Top::Throw(*reference_error);
7569}
7570
7571
lrn@chromium.org303ada72010-10-27 09:33:13 +00007572static MaybeObject* Runtime_StackOverflow(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007573 NoHandleAllocation na;
7574 return Top::StackOverflow();
7575}
7576
7577
lrn@chromium.org303ada72010-10-27 09:33:13 +00007578static MaybeObject* Runtime_StackGuard(Arguments args) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00007579 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007580
7581 // First check if this is a real stack overflow.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00007582 if (StackGuard::IsStackOverflow()) {
7583 return Runtime_StackOverflow(args);
7584 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007585
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007586 return Execution::HandleStackGuardInterrupt();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007587}
7588
7589
7590// NOTE: These PrintXXX functions are defined for all builds (not just
7591// DEBUG builds) because we may want to be able to trace function
7592// calls in all modes.
7593static void PrintString(String* str) {
7594 // not uncommon to have empty strings
7595 if (str->length() > 0) {
7596 SmartPointer<char> s =
7597 str->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
7598 PrintF("%s", *s);
7599 }
7600}
7601
7602
7603static void PrintObject(Object* obj) {
7604 if (obj->IsSmi()) {
7605 PrintF("%d", Smi::cast(obj)->value());
7606 } else if (obj->IsString() || obj->IsSymbol()) {
7607 PrintString(String::cast(obj));
7608 } else if (obj->IsNumber()) {
7609 PrintF("%g", obj->Number());
7610 } else if (obj->IsFailure()) {
7611 PrintF("<failure>");
7612 } else if (obj->IsUndefined()) {
7613 PrintF("<undefined>");
7614 } else if (obj->IsNull()) {
7615 PrintF("<null>");
7616 } else if (obj->IsTrue()) {
7617 PrintF("<true>");
7618 } else if (obj->IsFalse()) {
7619 PrintF("<false>");
7620 } else {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007621 PrintF("%p", reinterpret_cast<void*>(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007622 }
7623}
7624
7625
7626static int StackSize() {
7627 int n = 0;
7628 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
7629 return n;
7630}
7631
7632
7633static void PrintTransition(Object* result) {
7634 // indentation
7635 { const int nmax = 80;
7636 int n = StackSize();
7637 if (n <= nmax)
7638 PrintF("%4d:%*s", n, n, "");
7639 else
7640 PrintF("%4d:%*s", n, nmax, "...");
7641 }
7642
7643 if (result == NULL) {
7644 // constructor calls
7645 JavaScriptFrameIterator it;
7646 JavaScriptFrame* frame = it.frame();
7647 if (frame->IsConstructor()) PrintF("new ");
7648 // function name
7649 Object* fun = frame->function();
7650 if (fun->IsJSFunction()) {
7651 PrintObject(JSFunction::cast(fun)->shared()->name());
7652 } else {
7653 PrintObject(fun);
7654 }
7655 // function arguments
7656 // (we are intentionally only printing the actually
7657 // supplied parameters, not all parameters required)
7658 PrintF("(this=");
7659 PrintObject(frame->receiver());
7660 const int length = frame->GetProvidedParametersCount();
7661 for (int i = 0; i < length; i++) {
7662 PrintF(", ");
7663 PrintObject(frame->GetParameter(i));
7664 }
7665 PrintF(") {\n");
7666
7667 } else {
7668 // function result
7669 PrintF("} -> ");
7670 PrintObject(result);
7671 PrintF("\n");
7672 }
7673}
7674
7675
lrn@chromium.org303ada72010-10-27 09:33:13 +00007676static MaybeObject* Runtime_TraceEnter(Arguments args) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007677 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007678 NoHandleAllocation ha;
7679 PrintTransition(NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007680 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007681}
7682
7683
lrn@chromium.org303ada72010-10-27 09:33:13 +00007684static MaybeObject* Runtime_TraceExit(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007685 NoHandleAllocation ha;
7686 PrintTransition(args[0]);
7687 return args[0]; // return TOS
7688}
7689
7690
lrn@chromium.org303ada72010-10-27 09:33:13 +00007691static MaybeObject* Runtime_DebugPrint(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007692 NoHandleAllocation ha;
7693 ASSERT(args.length() == 1);
7694
7695#ifdef DEBUG
7696 if (args[0]->IsString()) {
7697 // If we have a string, assume it's a code "marker"
7698 // and print some interesting cpu debugging info.
7699 JavaScriptFrameIterator it;
7700 JavaScriptFrame* frame = it.frame();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00007701 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
7702 frame->fp(), frame->sp(), frame->caller_sp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007703 } else {
7704 PrintF("DebugPrint: ");
7705 }
7706 args[0]->Print();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00007707 if (args[0]->IsHeapObject()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007708 PrintF("\n");
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00007709 HeapObject::cast(args[0])->map()->Print();
7710 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007711#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007712 // ShortPrint is available in release mode. Print is not.
7713 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007714#endif
7715 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00007716 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007717
7718 return args[0]; // return TOS
7719}
7720
7721
lrn@chromium.org303ada72010-10-27 09:33:13 +00007722static MaybeObject* Runtime_DebugTrace(Arguments args) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007723 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007724 NoHandleAllocation ha;
7725 Top::PrintStack();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007726 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007727}
7728
7729
lrn@chromium.org303ada72010-10-27 09:33:13 +00007730static MaybeObject* Runtime_DateCurrentTime(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007731 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00007732 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007733
7734 // According to ECMA-262, section 15.9.1, page 117, the precision of
7735 // the number in a Date object representing a particular instant in
7736 // time is milliseconds. Therefore, we floor the result of getting
7737 // the OS time.
7738 double millis = floor(OS::TimeCurrentMillis());
7739 return Heap::NumberFromDouble(millis);
7740}
7741
7742
lrn@chromium.org303ada72010-10-27 09:33:13 +00007743static MaybeObject* Runtime_DateParseString(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007744 HandleScope scope;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007745 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007746
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007747 CONVERT_ARG_CHECKED(String, str, 0);
7748 FlattenString(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007749
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007750 CONVERT_ARG_CHECKED(JSArray, output, 1);
7751 RUNTIME_ASSERT(output->HasFastElements());
7752
7753 AssertNoAllocation no_allocation;
7754
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007755 FixedArray* output_array = FixedArray::cast(output->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007756 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
7757 bool result;
ager@chromium.org5ec48922009-05-05 07:25:34 +00007758 if (str->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007759 result = DateParser::Parse(str->ToAsciiVector(), output_array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007760 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00007761 ASSERT(str->IsTwoByteRepresentation());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007762 result = DateParser::Parse(str->ToUC16Vector(), output_array);
7763 }
7764
7765 if (result) {
7766 return *output;
7767 } else {
7768 return Heap::null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007769 }
7770}
7771
7772
lrn@chromium.org303ada72010-10-27 09:33:13 +00007773static MaybeObject* Runtime_DateLocalTimezone(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007774 NoHandleAllocation ha;
7775 ASSERT(args.length() == 1);
7776
7777 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00007778 const char* zone = OS::LocalTimezone(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007779 return Heap::AllocateStringFromUtf8(CStrVector(zone));
7780}
7781
7782
lrn@chromium.org303ada72010-10-27 09:33:13 +00007783static MaybeObject* Runtime_DateLocalTimeOffset(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007784 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00007785 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007786
7787 return Heap::NumberFromDouble(OS::LocalTimeOffset());
7788}
7789
7790
lrn@chromium.org303ada72010-10-27 09:33:13 +00007791static MaybeObject* Runtime_DateDaylightSavingsOffset(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007792 NoHandleAllocation ha;
7793 ASSERT(args.length() == 1);
7794
7795 CONVERT_DOUBLE_CHECKED(x, args[0]);
7796 return Heap::NumberFromDouble(OS::DaylightSavingsOffset(x));
7797}
7798
7799
lrn@chromium.org303ada72010-10-27 09:33:13 +00007800static MaybeObject* Runtime_GlobalReceiver(Arguments args) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007801 ASSERT(args.length() == 1);
7802 Object* global = args[0];
7803 if (!global->IsJSGlobalObject()) return Heap::null_value();
7804 return JSGlobalObject::cast(global)->global_receiver();
7805}
7806
7807
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00007808static MaybeObject* Runtime_ParseJson(Arguments args) {
7809 HandleScope scope;
7810 ASSERT_EQ(1, args.length());
7811 CONVERT_ARG_CHECKED(String, source, 0);
7812
7813 Handle<Object> result = JsonParser::Parse(source);
7814 if (result.is_null()) {
7815 // Syntax error or stack overflow in scanner.
7816 ASSERT(Top::has_pending_exception());
7817 return Failure::Exception();
7818 }
7819 return *result;
7820}
7821
7822
lrn@chromium.org303ada72010-10-27 09:33:13 +00007823static MaybeObject* Runtime_CompileString(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007824 HandleScope scope;
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00007825 ASSERT_EQ(1, args.length());
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00007826 CONVERT_ARG_CHECKED(String, source, 0);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007827
ager@chromium.org381abbb2009-02-25 13:23:22 +00007828 // Compile source string in the global context.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007829 Handle<Context> context(Top::context()->global_context());
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007830 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(source,
7831 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007832 true,
7833 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007834 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007835 Handle<JSFunction> fun =
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007836 Factory::NewFunctionFromSharedFunctionInfo(shared, context, NOT_TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007837 return *fun;
7838}
7839
7840
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00007841static ObjectPair CompileGlobalEval(Handle<String> source,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007842 Handle<Object> receiver,
7843 StrictModeFlag mode) {
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00007844 // Deal with a normal eval call with a string argument. Compile it
7845 // and return the compiled function bound in the local context.
7846 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
7847 source,
7848 Handle<Context>(Top::context()),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007849 Top::context()->IsGlobalContext(),
7850 mode);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00007851 if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
7852 Handle<JSFunction> compiled = Factory::NewFunctionFromSharedFunctionInfo(
7853 shared,
7854 Handle<Context>(Top::context()),
7855 NOT_TENURED);
7856 return MakePair(*compiled, *receiver);
7857}
7858
7859
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007860static ObjectPair Runtime_ResolvePossiblyDirectEval(Arguments args) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007861 ASSERT(args.length() == 4);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007862 if (!args[0]->IsJSFunction()) {
7863 return MakePair(Top::ThrowIllegalOperation(), NULL);
7864 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007865
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007866 HandleScope scope;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007867 Handle<JSFunction> callee = args.at<JSFunction>(0);
7868 Handle<Object> receiver; // Will be overwritten.
7869
7870 // Compute the calling context.
7871 Handle<Context> context = Handle<Context>(Top::context());
7872#ifdef DEBUG
7873 // Make sure Top::context() agrees with the old code that traversed
7874 // the stack frames to compute the context.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007875 StackFrameLocator locator;
7876 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007877 ASSERT(Context::cast(frame->context()) == *context);
7878#endif
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007879
7880 // Find where the 'eval' symbol is bound. It is unaliased only if
7881 // it is bound in the global context.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007882 int index = -1;
7883 PropertyAttributes attributes = ABSENT;
7884 while (true) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007885 receiver = context->Lookup(Factory::eval_symbol(), FOLLOW_PROTOTYPE_CHAIN,
7886 &index, &attributes);
iposva@chromium.org245aa852009-02-10 00:49:54 +00007887 // Stop search when eval is found or when the global context is
7888 // reached.
7889 if (attributes != ABSENT || context->IsGlobalContext()) break;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007890 if (context->is_function_context()) {
7891 context = Handle<Context>(Context::cast(context->closure()->context()));
7892 } else {
7893 context = Handle<Context>(context->previous());
7894 }
7895 }
7896
iposva@chromium.org245aa852009-02-10 00:49:54 +00007897 // If eval could not be resolved, it has been deleted and we need to
7898 // throw a reference error.
7899 if (attributes == ABSENT) {
7900 Handle<Object> name = Factory::eval_symbol();
7901 Handle<Object> reference_error =
7902 Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007903 return MakePair(Top::Throw(*reference_error), NULL);
iposva@chromium.org245aa852009-02-10 00:49:54 +00007904 }
7905
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007906 if (!context->IsGlobalContext()) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007907 // 'eval' is not bound in the global context. Just call the function
7908 // with the given arguments. This is not necessarily the global eval.
7909 if (receiver->IsContext()) {
7910 context = Handle<Context>::cast(receiver);
7911 receiver = Handle<Object>(context->get(index));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007912 } else if (receiver->IsJSContextExtensionObject()) {
7913 receiver = Handle<JSObject>(Top::context()->global()->global_receiver());
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007914 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007915 return MakePair(*callee, *receiver);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007916 }
7917
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007918 // 'eval' is bound in the global context, but it may have been overwritten.
7919 // Compare it to the builtin 'GlobalEval' function to make sure.
7920 if (*callee != Top::global_context()->global_eval_fun() ||
7921 !args[1]->IsString()) {
7922 return MakePair(*callee, Top::context()->global()->global_receiver());
7923 }
7924
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007925 ASSERT(args[3]->IsSmi());
7926 return CompileGlobalEval(args.at<String>(1),
7927 args.at<Object>(2),
7928 static_cast<StrictModeFlag>(
7929 Smi::cast(args[3])->value()));
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00007930}
7931
7932
7933static ObjectPair Runtime_ResolvePossiblyDirectEvalNoLookup(Arguments args) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007934 ASSERT(args.length() == 4);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00007935 if (!args[0]->IsJSFunction()) {
7936 return MakePair(Top::ThrowIllegalOperation(), NULL);
7937 }
7938
7939 HandleScope scope;
7940 Handle<JSFunction> callee = args.at<JSFunction>(0);
7941
7942 // 'eval' is bound in the global context, but it may have been overwritten.
7943 // Compare it to the builtin 'GlobalEval' function to make sure.
7944 if (*callee != Top::global_context()->global_eval_fun() ||
7945 !args[1]->IsString()) {
7946 return MakePair(*callee, Top::context()->global()->global_receiver());
7947 }
7948
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007949 ASSERT(args[3]->IsSmi());
7950 return CompileGlobalEval(args.at<String>(1),
7951 args.at<Object>(2),
7952 static_cast<StrictModeFlag>(
7953 Smi::cast(args[3])->value()));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007954}
7955
7956
lrn@chromium.org303ada72010-10-27 09:33:13 +00007957static MaybeObject* Runtime_SetNewFunctionAttributes(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007958 // This utility adjusts the property attributes for newly created Function
7959 // object ("new Function(...)") by changing the map.
7960 // All it does is changing the prototype property to enumerable
7961 // as specified in ECMA262, 15.3.5.2.
7962 HandleScope scope;
7963 ASSERT(args.length() == 1);
7964 CONVERT_ARG_CHECKED(JSFunction, func, 0);
7965 ASSERT(func->map()->instance_type() ==
7966 Top::function_instance_map()->instance_type());
7967 ASSERT(func->map()->instance_size() ==
7968 Top::function_instance_map()->instance_size());
7969 func->set_map(*Top::function_instance_map());
7970 return *func;
7971}
7972
7973
lrn@chromium.org303ada72010-10-27 09:33:13 +00007974static MaybeObject* Runtime_AllocateInNewSpace(Arguments args) {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00007975 // Allocate a block of memory in NewSpace (filled with a filler).
7976 // Use as fallback for allocation in generated code when NewSpace
7977 // is full.
7978 ASSERT(args.length() == 1);
7979 CONVERT_ARG_CHECKED(Smi, size_smi, 0);
7980 int size = size_smi->value();
7981 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
7982 RUNTIME_ASSERT(size > 0);
7983 static const int kMinFreeNewSpaceAfterGC =
7984 Heap::InitialSemiSpaceSize() * 3/4;
7985 RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007986 Object* allocation;
7987 { MaybeObject* maybe_allocation = Heap::new_space()->AllocateRaw(size);
7988 if (maybe_allocation->ToObject(&allocation)) {
7989 Heap::CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
7990 }
7991 return maybe_allocation;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00007992 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00007993}
7994
7995
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007996// Push an object unto an array of objects if it is not already in the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007997// array. Returns true if the element was pushed on the stack and
7998// false otherwise.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007999static MaybeObject* Runtime_PushIfAbsent(Arguments args) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008000 ASSERT(args.length() == 2);
8001 CONVERT_CHECKED(JSArray, array, args[0]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008002 CONVERT_CHECKED(JSObject, element, args[1]);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008003 RUNTIME_ASSERT(array->HasFastElements());
8004 int length = Smi::cast(array->length())->value();
8005 FixedArray* elements = FixedArray::cast(array->elements());
8006 for (int i = 0; i < length; i++) {
8007 if (elements->get(i) == element) return Heap::false_value();
8008 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00008009 Object* obj;
8010 { MaybeObject* maybe_obj = array->SetFastElement(length, element);
8011 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8012 }
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008013 return Heap::true_value();
8014}
8015
8016
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008017/**
8018 * A simple visitor visits every element of Array's.
8019 * The backend storage can be a fixed array for fast elements case,
8020 * or a dictionary for sparse array. Since Dictionary is a subtype
8021 * of FixedArray, the class can be used by both fast and slow cases.
8022 * The second parameter of the constructor, fast_elements, specifies
8023 * whether the storage is a FixedArray or Dictionary.
8024 *
8025 * An index limit is used to deal with the situation that a result array
8026 * length overflows 32-bit non-negative integer.
8027 */
8028class ArrayConcatVisitor {
8029 public:
8030 ArrayConcatVisitor(Handle<FixedArray> storage,
8031 uint32_t index_limit,
8032 bool fast_elements) :
8033 storage_(storage), index_limit_(index_limit),
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008034 index_offset_(0), fast_elements_(fast_elements) { }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008035
8036 void visit(uint32_t i, Handle<Object> elm) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008037 if (i >= index_limit_ - index_offset_) return;
8038 uint32_t index = index_offset_ + i;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008039
8040 if (fast_elements_) {
8041 ASSERT(index < static_cast<uint32_t>(storage_->length()));
8042 storage_->set(index, *elm);
8043
8044 } else {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00008045 Handle<NumberDictionary> dict = Handle<NumberDictionary>::cast(storage_);
8046 Handle<NumberDictionary> result =
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008047 Factory::DictionaryAtNumberPut(dict, index, elm);
8048 if (!result.is_identical_to(dict))
8049 storage_ = result;
8050 }
8051 }
8052
8053 void increase_index_offset(uint32_t delta) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008054 if (index_limit_ - index_offset_ < delta) {
8055 index_offset_ = index_limit_;
8056 } else {
8057 index_offset_ += delta;
8058 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008059 }
8060
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00008061 Handle<FixedArray> storage() { return storage_; }
8062
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008063 private:
8064 Handle<FixedArray> storage_;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008065 // Limit on the accepted indices. Elements with indices larger than the
8066 // limit are ignored by the visitor.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008067 uint32_t index_limit_;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008068 // Index after last seen index. Always less than or equal to index_limit_.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008069 uint32_t index_offset_;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00008070 const bool fast_elements_;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008071};
8072
8073
ager@chromium.org3811b432009-10-28 14:53:37 +00008074template<class ExternalArrayClass, class ElementType>
8075static uint32_t IterateExternalArrayElements(Handle<JSObject> receiver,
8076 bool elements_are_ints,
8077 bool elements_are_guaranteed_smis,
8078 uint32_t range,
8079 ArrayConcatVisitor* visitor) {
8080 Handle<ExternalArrayClass> array(
8081 ExternalArrayClass::cast(receiver->elements()));
8082 uint32_t len = Min(static_cast<uint32_t>(array->length()), range);
8083
8084 if (visitor != NULL) {
8085 if (elements_are_ints) {
8086 if (elements_are_guaranteed_smis) {
8087 for (uint32_t j = 0; j < len; j++) {
8088 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get(j))));
8089 visitor->visit(j, e);
8090 }
8091 } else {
8092 for (uint32_t j = 0; j < len; j++) {
8093 int64_t val = static_cast<int64_t>(array->get(j));
8094 if (Smi::IsValid(static_cast<intptr_t>(val))) {
8095 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
8096 visitor->visit(j, e);
8097 } else {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00008098 Handle<Object> e =
8099 Factory::NewNumber(static_cast<ElementType>(val));
ager@chromium.org3811b432009-10-28 14:53:37 +00008100 visitor->visit(j, e);
8101 }
8102 }
8103 }
8104 } else {
8105 for (uint32_t j = 0; j < len; j++) {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00008106 Handle<Object> e = Factory::NewNumber(array->get(j));
ager@chromium.org3811b432009-10-28 14:53:37 +00008107 visitor->visit(j, e);
8108 }
8109 }
8110 }
8111
8112 return len;
8113}
8114
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008115/**
8116 * A helper function that visits elements of a JSObject. Only elements
8117 * whose index between 0 and range (exclusive) are visited.
8118 *
8119 * If the third parameter, visitor, is not NULL, the visitor is called
8120 * with parameters, 'visitor_index_offset + element index' and the element.
8121 *
8122 * It returns the number of visisted elements.
8123 */
8124static uint32_t IterateElements(Handle<JSObject> receiver,
8125 uint32_t range,
8126 ArrayConcatVisitor* visitor) {
8127 uint32_t num_of_elements = 0;
8128
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008129 switch (receiver->GetElementsKind()) {
8130 case JSObject::FAST_ELEMENTS: {
8131 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
8132 uint32_t len = elements->length();
8133 if (range < len) {
8134 len = range;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008135 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008136
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008137 for (uint32_t j = 0; j < len; j++) {
8138 Handle<Object> e(elements->get(j));
8139 if (!e->IsTheHole()) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008140 num_of_elements++;
8141 if (visitor) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008142 visitor->visit(j, e);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008143 }
8144 }
8145 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008146 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008147 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008148 case JSObject::PIXEL_ELEMENTS: {
8149 Handle<PixelArray> pixels(PixelArray::cast(receiver->elements()));
8150 uint32_t len = pixels->length();
8151 if (range < len) {
8152 len = range;
8153 }
8154
8155 for (uint32_t j = 0; j < len; j++) {
8156 num_of_elements++;
8157 if (visitor != NULL) {
8158 Handle<Smi> e(Smi::FromInt(pixels->get(j)));
8159 visitor->visit(j, e);
8160 }
8161 }
8162 break;
8163 }
ager@chromium.org3811b432009-10-28 14:53:37 +00008164 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
8165 num_of_elements =
8166 IterateExternalArrayElements<ExternalByteArray, int8_t>(
8167 receiver, true, true, range, visitor);
8168 break;
8169 }
8170 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
8171 num_of_elements =
8172 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
8173 receiver, true, true, range, visitor);
8174 break;
8175 }
8176 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
8177 num_of_elements =
8178 IterateExternalArrayElements<ExternalShortArray, int16_t>(
8179 receiver, true, true, range, visitor);
8180 break;
8181 }
8182 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
8183 num_of_elements =
8184 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
8185 receiver, true, true, range, visitor);
8186 break;
8187 }
8188 case JSObject::EXTERNAL_INT_ELEMENTS: {
8189 num_of_elements =
8190 IterateExternalArrayElements<ExternalIntArray, int32_t>(
8191 receiver, true, false, range, visitor);
8192 break;
8193 }
8194 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
8195 num_of_elements =
8196 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
8197 receiver, true, false, range, visitor);
8198 break;
8199 }
8200 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
8201 num_of_elements =
8202 IterateExternalArrayElements<ExternalFloatArray, float>(
8203 receiver, false, false, range, visitor);
8204 break;
8205 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008206 case JSObject::DICTIONARY_ELEMENTS: {
8207 Handle<NumberDictionary> dict(receiver->element_dictionary());
8208 uint32_t capacity = dict->Capacity();
8209 for (uint32_t j = 0; j < capacity; j++) {
8210 Handle<Object> k(dict->KeyAt(j));
8211 if (dict->IsKey(*k)) {
8212 ASSERT(k->IsNumber());
8213 uint32_t index = static_cast<uint32_t>(k->Number());
8214 if (index < range) {
8215 num_of_elements++;
8216 if (visitor) {
8217 visitor->visit(index, Handle<Object>(dict->ValueAt(j)));
8218 }
8219 }
8220 }
8221 }
8222 break;
8223 }
8224 default:
8225 UNREACHABLE();
8226 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008227 }
8228
8229 return num_of_elements;
8230}
8231
8232
8233/**
8234 * A helper function that visits elements of an Array object, and elements
8235 * on its prototypes.
8236 *
8237 * Elements on prototypes are visited first, and only elements whose indices
8238 * less than Array length are visited.
8239 *
8240 * If a ArrayConcatVisitor object is given, the visitor is called with
8241 * parameters, element's index + visitor_index_offset and the element.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008242 *
8243 * The returned number of elements is an upper bound on the actual number
8244 * of elements added. If the same element occurs in more than one object
8245 * in the array's prototype chain, it will be counted more than once, but
8246 * will only occur once in the result.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008247 */
8248static uint32_t IterateArrayAndPrototypeElements(Handle<JSArray> array,
8249 ArrayConcatVisitor* visitor) {
8250 uint32_t range = static_cast<uint32_t>(array->length()->Number());
8251 Handle<Object> obj = array;
8252
8253 static const int kEstimatedPrototypes = 3;
8254 List< Handle<JSObject> > objects(kEstimatedPrototypes);
8255
8256 // Visit prototype first. If an element on the prototype is shadowed by
8257 // the inheritor using the same index, the ArrayConcatVisitor visits
8258 // the prototype element before the shadowing element.
8259 // The visitor can simply overwrite the old value by new value using
8260 // the same index. This follows Array::concat semantics.
8261 while (!obj->IsNull()) {
8262 objects.Add(Handle<JSObject>::cast(obj));
8263 obj = Handle<Object>(obj->GetPrototype());
8264 }
8265
8266 uint32_t nof_elements = 0;
8267 for (int i = objects.length() - 1; i >= 0; i--) {
8268 Handle<JSObject> obj = objects[i];
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008269 uint32_t encountered_elements =
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008270 IterateElements(Handle<JSObject>::cast(obj), range, visitor);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008271
8272 if (encountered_elements > JSObject::kMaxElementCount - nof_elements) {
8273 nof_elements = JSObject::kMaxElementCount;
8274 } else {
8275 nof_elements += encountered_elements;
8276 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008277 }
8278
8279 return nof_elements;
8280}
8281
8282
8283/**
8284 * A helper function of Runtime_ArrayConcat.
8285 *
8286 * The first argument is an Array of arrays and objects. It is the
8287 * same as the arguments array of Array::concat JS function.
8288 *
8289 * If an argument is an Array object, the function visits array
8290 * elements. If an argument is not an Array object, the function
8291 * visits the object as if it is an one-element array.
8292 *
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008293 * If the result array index overflows 32-bit unsigned integer, the rounded
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008294 * non-negative number is used as new length. For example, if one
8295 * array length is 2^32 - 1, second array length is 1, the
8296 * concatenated array length is 0.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008297 * TODO(lrn) Change length behavior to ECMAScript 5 specification (length
8298 * is one more than the last array index to get a value assigned).
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008299 */
8300static uint32_t IterateArguments(Handle<JSArray> arguments,
8301 ArrayConcatVisitor* visitor) {
8302 uint32_t visited_elements = 0;
8303 uint32_t num_of_args = static_cast<uint32_t>(arguments->length()->Number());
8304
8305 for (uint32_t i = 0; i < num_of_args; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008306 Object *element;
8307 MaybeObject* maybe_element = arguments->GetElement(i);
8308 // This if() is not expected to fail, but we have the check in the
8309 // interest of hardening the runtime calls.
8310 if (maybe_element->ToObject(&element)) {
8311 Handle<Object> obj(element);
8312 if (obj->IsJSArray()) {
8313 Handle<JSArray> array = Handle<JSArray>::cast(obj);
8314 uint32_t len = static_cast<uint32_t>(array->length()->Number());
8315 uint32_t nof_elements =
8316 IterateArrayAndPrototypeElements(array, visitor);
8317 // Total elements of array and its prototype chain can be more than
8318 // the array length, but ArrayConcat can only concatenate at most
8319 // the array length number of elements. We use the length as an estimate
8320 // for the actual number of elements added.
8321 uint32_t added_elements = (nof_elements > len) ? len : nof_elements;
8322 if (JSArray::kMaxElementCount - visited_elements < added_elements) {
8323 visited_elements = JSArray::kMaxElementCount;
8324 } else {
8325 visited_elements += added_elements;
8326 }
8327 if (visitor) visitor->increase_index_offset(len);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008328 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008329 if (visitor) {
8330 visitor->visit(0, obj);
8331 visitor->increase_index_offset(1);
8332 }
8333 if (visited_elements < JSArray::kMaxElementCount) {
8334 visited_elements++;
8335 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008336 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008337 }
8338 }
8339 return visited_elements;
8340}
8341
8342
8343/**
8344 * Array::concat implementation.
8345 * See ECMAScript 262, 15.4.4.4.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008346 * TODO(lrn): Fix non-compliance for very large concatenations and update to
8347 * following the ECMAScript 5 specification.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008348 */
lrn@chromium.org303ada72010-10-27 09:33:13 +00008349static MaybeObject* Runtime_ArrayConcat(Arguments args) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008350 ASSERT(args.length() == 1);
8351 HandleScope handle_scope;
8352
8353 CONVERT_CHECKED(JSArray, arg_arrays, args[0]);
8354 Handle<JSArray> arguments(arg_arrays);
8355
8356 // Pass 1: estimate the number of elements of the result
8357 // (it could be more than real numbers if prototype has elements).
8358 uint32_t result_length = 0;
8359 uint32_t num_of_args = static_cast<uint32_t>(arguments->length()->Number());
8360
8361 { AssertNoAllocation nogc;
8362 for (uint32_t i = 0; i < num_of_args; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008363 Object* obj;
8364 MaybeObject* maybe_object = arguments->GetElement(i);
8365 // This if() is not expected to fail, but we have the check in the
8366 // interest of hardening the runtime calls.
8367 if (maybe_object->ToObject(&obj)) {
8368 uint32_t length_estimate;
8369 if (obj->IsJSArray()) {
8370 length_estimate =
8371 static_cast<uint32_t>(JSArray::cast(obj)->length()->Number());
8372 } else {
8373 length_estimate = 1;
8374 }
8375 if (JSObject::kMaxElementCount - result_length < length_estimate) {
8376 result_length = JSObject::kMaxElementCount;
8377 break;
8378 }
8379 result_length += length_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008380 }
8381 }
8382 }
8383
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00008384 // Allocate an empty array, will set map, length, and content later.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008385 Handle<JSArray> result = Factory::NewJSArray(0);
8386
8387 uint32_t estimate_nof_elements = IterateArguments(arguments, NULL);
8388 // If estimated number of elements is more than half of length, a
8389 // fixed array (fast case) is more time and space-efficient than a
8390 // dictionary.
8391 bool fast_case = (estimate_nof_elements * 2) >= result_length;
8392
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00008393 Handle<Map> map;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008394 Handle<FixedArray> storage;
8395 if (fast_case) {
8396 // The backing storage array must have non-existing elements to
8397 // preserve holes across concat operations.
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00008398 map = Factory::GetFastElementsMap(Handle<Map>(result->map()));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008399 storage = Factory::NewFixedArrayWithHoles(result_length);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008400 } else {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00008401 map = Factory::GetSlowElementsMap(Handle<Map>(result->map()));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008402 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
8403 uint32_t at_least_space_for = estimate_nof_elements +
8404 (estimate_nof_elements >> 2);
8405 storage = Handle<FixedArray>::cast(
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00008406 Factory::NewNumberDictionary(at_least_space_for));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008407 }
8408
8409 Handle<Object> len = Factory::NewNumber(static_cast<double>(result_length));
8410
8411 ArrayConcatVisitor visitor(storage, result_length, fast_case);
8412
8413 IterateArguments(arguments, &visitor);
8414
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00008415 // Please note:
8416 // - the storage might have been changed in the visitor;
8417 // - the map and the storage must be set together to avoid breaking
8418 // the invariant that the map describes the array's elements.
8419 result->set_map(*map);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008420 result->set_length(*len);
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00008421 result->set_elements(*visitor.storage());
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008422
8423 return *result;
8424}
8425
8426
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008427// This will not allocate (flatten the string), but it may run
8428// very slowly for very deeply nested ConsStrings. For debugging use only.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008429static MaybeObject* Runtime_GlobalPrint(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008430 NoHandleAllocation ha;
8431 ASSERT(args.length() == 1);
8432
8433 CONVERT_CHECKED(String, string, args[0]);
8434 StringInputBuffer buffer(string);
8435 while (buffer.has_more()) {
8436 uint16_t character = buffer.GetNext();
8437 PrintF("%c", character);
8438 }
8439 return string;
8440}
8441
ager@chromium.org5ec48922009-05-05 07:25:34 +00008442// Moves all own elements of an object, that are below a limit, to positions
8443// starting at zero. All undefined values are placed after non-undefined values,
8444// and are followed by non-existing element. Does not change the length
8445// property.
8446// Returns the number of non-undefined elements collected.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008447static MaybeObject* Runtime_RemoveArrayHoles(Arguments args) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00008448 ASSERT(args.length() == 2);
8449 CONVERT_CHECKED(JSObject, object, args[0]);
8450 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
8451 return object->PrepareElementsForSort(limit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008452}
8453
8454
8455// Move contents of argument 0 (an array) to argument 1 (an array)
lrn@chromium.org303ada72010-10-27 09:33:13 +00008456static MaybeObject* Runtime_MoveArrayContents(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008457 ASSERT(args.length() == 2);
8458 CONVERT_CHECKED(JSArray, from, args[0]);
8459 CONVERT_CHECKED(JSArray, to, args[1]);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00008460 HeapObject* new_elements = from->elements();
lrn@chromium.org303ada72010-10-27 09:33:13 +00008461 MaybeObject* maybe_new_map;
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00008462 if (new_elements->map() == Heap::fixed_array_map() ||
8463 new_elements->map() == Heap::fixed_cow_array_map()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008464 maybe_new_map = to->map()->GetFastElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00008465 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008466 maybe_new_map = to->map()->GetSlowElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00008467 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00008468 Object* new_map;
8469 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00008470 to->set_map(Map::cast(new_map));
8471 to->set_elements(new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008472 to->set_length(from->length());
lrn@chromium.org303ada72010-10-27 09:33:13 +00008473 Object* obj;
8474 { MaybeObject* maybe_obj = from->ResetElements();
8475 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8476 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008477 from->set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008478 return to;
8479}
8480
8481
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008482// How many elements does this object/array have?
lrn@chromium.org303ada72010-10-27 09:33:13 +00008483static MaybeObject* Runtime_EstimateNumberOfElements(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008484 ASSERT(args.length() == 1);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008485 CONVERT_CHECKED(JSObject, object, args[0]);
8486 HeapObject* elements = object->elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008487 if (elements->IsDictionary()) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00008488 return Smi::FromInt(NumberDictionary::cast(elements)->NumberOfElements());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008489 } else if (object->IsJSArray()) {
8490 return JSArray::cast(object)->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008491 } else {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008492 return Smi::FromInt(FixedArray::cast(elements)->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008493 }
8494}
8495
8496
lrn@chromium.org303ada72010-10-27 09:33:13 +00008497static MaybeObject* Runtime_SwapElements(Arguments args) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008498 HandleScope handle_scope;
8499
8500 ASSERT_EQ(3, args.length());
8501
ager@chromium.orgac091b72010-05-05 07:34:42 +00008502 CONVERT_ARG_CHECKED(JSObject, object, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008503 Handle<Object> key1 = args.at<Object>(1);
8504 Handle<Object> key2 = args.at<Object>(2);
8505
8506 uint32_t index1, index2;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008507 if (!key1->ToArrayIndex(&index1)
8508 || !key2->ToArrayIndex(&index2)) {
ager@chromium.orgac091b72010-05-05 07:34:42 +00008509 return Top::ThrowIllegalOperation();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008510 }
8511
ager@chromium.orgac091b72010-05-05 07:34:42 +00008512 Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
8513 Handle<Object> tmp1 = GetElement(jsobject, index1);
8514 Handle<Object> tmp2 = GetElement(jsobject, index2);
8515
8516 SetElement(jsobject, index1, tmp2);
8517 SetElement(jsobject, index2, tmp1);
8518
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008519 return Heap::undefined_value();
8520}
8521
8522
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008523// Returns an array that tells you where in the [0, length) interval an array
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008524// might have elements. Can either return keys (positive integers) or
8525// intervals (pair of a negative integer (-start-1) followed by a
8526// positive (length)) or undefined values.
8527// Intervals can span over some keys that are not in the object.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008528static MaybeObject* Runtime_GetArrayKeys(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008529 ASSERT(args.length() == 2);
8530 HandleScope scope;
ager@chromium.org5ec48922009-05-05 07:25:34 +00008531 CONVERT_ARG_CHECKED(JSObject, array, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008532 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008533 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008534 // Create an array and get all the keys into it, then remove all the
8535 // keys that are not integers in the range 0 to length-1.
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008536 Handle<FixedArray> keys = GetKeysInFixedArrayFor(array, INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008537 int keys_length = keys->length();
8538 for (int i = 0; i < keys_length; i++) {
8539 Object* key = keys->get(i);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008540 uint32_t index = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008541 if (!key->ToArrayIndex(&index) || index >= length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008542 // Zap invalid keys.
8543 keys->set_undefined(i);
8544 }
8545 }
8546 return *Factory::NewJSArrayWithElements(keys);
8547 } else {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008548 ASSERT(array->HasFastElements());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008549 Handle<FixedArray> single_interval = Factory::NewFixedArray(2);
8550 // -1 means start of array.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008551 single_interval->set(0, Smi::FromInt(-1));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008552 uint32_t actual_length =
8553 static_cast<uint32_t>(FixedArray::cast(array->elements())->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +00008554 uint32_t min_length = actual_length < length ? actual_length : length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008555 Handle<Object> length_object =
ager@chromium.org5ec48922009-05-05 07:25:34 +00008556 Factory::NewNumber(static_cast<double>(min_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008557 single_interval->set(1, *length_object);
8558 return *Factory::NewJSArrayWithElements(single_interval);
8559 }
8560}
8561
8562
8563// DefineAccessor takes an optional final argument which is the
8564// property attributes (eg, DONT_ENUM, DONT_DELETE). IMPORTANT: due
8565// to the way accessors are implemented, it is set for both the getter
8566// and setter on the first call to DefineAccessor and ignored on
8567// subsequent calls.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008568static MaybeObject* Runtime_DefineAccessor(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008569 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
8570 // Compute attributes.
8571 PropertyAttributes attributes = NONE;
8572 if (args.length() == 5) {
8573 CONVERT_CHECKED(Smi, attrs, args[4]);
8574 int value = attrs->value();
8575 // Only attribute bits should be set.
8576 ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
8577 attributes = static_cast<PropertyAttributes>(value);
8578 }
8579
8580 CONVERT_CHECKED(JSObject, obj, args[0]);
8581 CONVERT_CHECKED(String, name, args[1]);
8582 CONVERT_CHECKED(Smi, flag, args[2]);
8583 CONVERT_CHECKED(JSFunction, fun, args[3]);
8584 return obj->DefineAccessor(name, flag->value() == 0, fun, attributes);
8585}
8586
8587
lrn@chromium.org303ada72010-10-27 09:33:13 +00008588static MaybeObject* Runtime_LookupAccessor(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008589 ASSERT(args.length() == 3);
8590 CONVERT_CHECKED(JSObject, obj, args[0]);
8591 CONVERT_CHECKED(String, name, args[1]);
8592 CONVERT_CHECKED(Smi, flag, args[2]);
8593 return obj->LookupAccessor(name, flag->value() == 0);
8594}
8595
8596
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008597#ifdef ENABLE_DEBUGGER_SUPPORT
lrn@chromium.org303ada72010-10-27 09:33:13 +00008598static MaybeObject* Runtime_DebugBreak(Arguments args) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008599 ASSERT(args.length() == 0);
8600 return Execution::DebugBreakHelper();
8601}
8602
8603
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008604// Helper functions for wrapping and unwrapping stack frame ids.
8605static Smi* WrapFrameId(StackFrame::Id id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +00008606 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008607 return Smi::FromInt(id >> 2);
8608}
8609
8610
8611static StackFrame::Id UnwrapFrameId(Smi* wrapped) {
8612 return static_cast<StackFrame::Id>(wrapped->value() << 2);
8613}
8614
8615
8616// Adds a JavaScript function as a debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +00008617// args[0]: debug event listener function to set or null or undefined for
8618// clearing the event listener function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008619// args[1]: object supplied during callback
lrn@chromium.org303ada72010-10-27 09:33:13 +00008620static MaybeObject* Runtime_SetDebugEventListener(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008621 ASSERT(args.length() == 2);
iposva@chromium.org245aa852009-02-10 00:49:54 +00008622 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
8623 args[0]->IsUndefined() ||
8624 args[0]->IsNull());
8625 Handle<Object> callback = args.at<Object>(0);
8626 Handle<Object> data = args.at<Object>(1);
8627 Debugger::SetEventListener(callback, data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008628
8629 return Heap::undefined_value();
8630}
8631
8632
lrn@chromium.org303ada72010-10-27 09:33:13 +00008633static MaybeObject* Runtime_Break(Arguments args) {
mads.s.ager31e71382008-08-13 09:32:07 +00008634 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008635 StackGuard::DebugBreak();
8636 return Heap::undefined_value();
8637}
8638
8639
lrn@chromium.org303ada72010-10-27 09:33:13 +00008640static MaybeObject* DebugLookupResultValue(Object* receiver, String* name,
8641 LookupResult* result,
8642 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00008643 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008644 switch (result->type()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008645 case NORMAL:
8646 value = result->holder()->GetNormalizedProperty(result);
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00008647 if (value->IsTheHole()) {
8648 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008649 }
8650 return value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00008651 case FIELD:
8652 value =
8653 JSObject::cast(
8654 result->holder())->FastPropertyAt(result->GetFieldIndex());
8655 if (value->IsTheHole()) {
8656 return Heap::undefined_value();
8657 }
8658 return value;
8659 case CONSTANT_FUNCTION:
8660 return result->GetConstantFunction();
8661 case CALLBACKS: {
8662 Object* structure = result->GetCallbackObject();
kasperl@chromium.org71affb52009-05-26 05:44:31 +00008663 if (structure->IsProxy() || structure->IsAccessorInfo()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008664 MaybeObject* maybe_value = receiver->GetPropertyWithCallback(
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00008665 receiver, structure, name, result->holder());
lrn@chromium.org303ada72010-10-27 09:33:13 +00008666 if (!maybe_value->ToObject(&value)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008667 if (maybe_value->IsRetryAfterGC()) return maybe_value;
lrn@chromium.org303ada72010-10-27 09:33:13 +00008668 ASSERT(maybe_value->IsException());
8669 maybe_value = Top::pending_exception();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00008670 Top::clear_pending_exception();
8671 if (caught_exception != NULL) {
8672 *caught_exception = true;
8673 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00008674 return maybe_value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00008675 }
8676 return value;
8677 } else {
8678 return Heap::undefined_value();
8679 }
8680 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008681 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008682 case MAP_TRANSITION:
8683 case CONSTANT_TRANSITION:
8684 case NULL_DESCRIPTOR:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008685 return Heap::undefined_value();
8686 default:
8687 UNREACHABLE();
8688 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008689 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008690 return Heap::undefined_value();
8691}
8692
8693
ager@chromium.org32912102009-01-16 10:38:43 +00008694// Get debugger related details for an object property.
8695// args[0]: object holding property
8696// args[1]: name of the property
8697//
8698// The array returned contains the following information:
8699// 0: Property value
8700// 1: Property details
8701// 2: Property value is exception
8702// 3: Getter function if defined
8703// 4: Setter function if defined
8704// Items 2-4 are only filled if the property has either a getter or a setter
8705// defined through __defineGetter__ and/or __defineSetter__.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008706static MaybeObject* Runtime_DebugGetPropertyDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008707 HandleScope scope;
8708
8709 ASSERT(args.length() == 2);
8710
8711 CONVERT_ARG_CHECKED(JSObject, obj, 0);
8712 CONVERT_ARG_CHECKED(String, name, 1);
8713
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00008714 // Make sure to set the current context to the context before the debugger was
8715 // entered (if the debugger is entered). The reason for switching context here
8716 // is that for some property lookups (accessors and interceptors) callbacks
8717 // into the embedding application can occour, and the embedding application
8718 // could have the assumption that its own global context is the current
8719 // context and not some internal debugger context.
8720 SaveContext save;
8721 if (Debug::InDebugger()) {
8722 Top::set_context(*Debug::debugger_entry()->GetContext());
8723 }
8724
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008725 // Skip the global proxy as it has no properties and always delegates to the
8726 // real global object.
8727 if (obj->IsJSGlobalProxy()) {
8728 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
8729 }
8730
8731
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008732 // Check if the name is trivially convertible to an index and get the element
8733 // if so.
8734 uint32_t index;
8735 if (name->AsArrayIndex(&index)) {
8736 Handle<FixedArray> details = Factory::NewFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008737 Object* element_or_char;
8738 { MaybeObject* maybe_element_or_char =
8739 Runtime::GetElementOrCharAt(obj, index);
8740 if (!maybe_element_or_char->ToObject(&element_or_char)) {
8741 return maybe_element_or_char;
8742 }
8743 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008744 details->set(0, element_or_char);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008745 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
8746 return *Factory::NewJSArrayWithElements(details);
8747 }
8748
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008749 // Find the number of objects making up this.
8750 int length = LocalPrototypeChainLength(*obj);
8751
8752 // Try local lookup on each of the objects.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008753 Handle<JSObject> jsproto = obj;
8754 for (int i = 0; i < length; i++) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008755 LookupResult result;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008756 jsproto->LocalLookup(*name, &result);
8757 if (result.IsProperty()) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008758 // LookupResult is not GC safe as it holds raw object pointers.
8759 // GC can happen later in this code so put the required fields into
8760 // local variables using handles when required for later use.
8761 PropertyType result_type = result.type();
8762 Handle<Object> result_callback_obj;
8763 if (result_type == CALLBACKS) {
8764 result_callback_obj = Handle<Object>(result.GetCallbackObject());
8765 }
8766 Smi* property_details = result.GetPropertyDetails().AsSmi();
8767 // DebugLookupResultValue can cause GC so details from LookupResult needs
8768 // to be copied to handles before this.
8769 bool caught_exception = false;
lrn@chromium.org303ada72010-10-27 09:33:13 +00008770 Object* raw_value;
8771 { MaybeObject* maybe_raw_value =
8772 DebugLookupResultValue(*obj, *name, &result, &caught_exception);
8773 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
8774 }
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008775 Handle<Object> value(raw_value);
8776
8777 // If the callback object is a fixed array then it contains JavaScript
8778 // getter and/or setter.
8779 bool hasJavaScriptAccessors = result_type == CALLBACKS &&
8780 result_callback_obj->IsFixedArray();
8781 Handle<FixedArray> details =
8782 Factory::NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
8783 details->set(0, *value);
8784 details->set(1, property_details);
8785 if (hasJavaScriptAccessors) {
8786 details->set(2,
8787 caught_exception ? Heap::true_value()
8788 : Heap::false_value());
8789 details->set(3, FixedArray::cast(*result_callback_obj)->get(0));
8790 details->set(4, FixedArray::cast(*result_callback_obj)->get(1));
8791 }
8792
8793 return *Factory::NewJSArrayWithElements(details);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008794 }
8795 if (i < length - 1) {
8796 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
8797 }
8798 }
8799
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008800 return Heap::undefined_value();
8801}
8802
8803
lrn@chromium.org303ada72010-10-27 09:33:13 +00008804static MaybeObject* Runtime_DebugGetProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008805 HandleScope scope;
8806
8807 ASSERT(args.length() == 2);
8808
8809 CONVERT_ARG_CHECKED(JSObject, obj, 0);
8810 CONVERT_ARG_CHECKED(String, name, 1);
8811
8812 LookupResult result;
8813 obj->Lookup(*name, &result);
8814 if (result.IsProperty()) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +00008815 return DebugLookupResultValue(*obj, *name, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008816 }
8817 return Heap::undefined_value();
8818}
8819
8820
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008821// Return the property type calculated from the property details.
8822// args[0]: smi with property details.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008823static MaybeObject* Runtime_DebugPropertyTypeFromDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008824 ASSERT(args.length() == 1);
8825 CONVERT_CHECKED(Smi, details, args[0]);
8826 PropertyType type = PropertyDetails(details).type();
8827 return Smi::FromInt(static_cast<int>(type));
8828}
8829
8830
8831// Return the property attribute calculated from the property details.
8832// args[0]: smi with property details.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008833static MaybeObject* Runtime_DebugPropertyAttributesFromDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008834 ASSERT(args.length() == 1);
8835 CONVERT_CHECKED(Smi, details, args[0]);
8836 PropertyAttributes attributes = PropertyDetails(details).attributes();
8837 return Smi::FromInt(static_cast<int>(attributes));
8838}
8839
8840
8841// Return the property insertion index calculated from the property details.
8842// args[0]: smi with property details.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008843static MaybeObject* Runtime_DebugPropertyIndexFromDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008844 ASSERT(args.length() == 1);
8845 CONVERT_CHECKED(Smi, details, args[0]);
8846 int index = PropertyDetails(details).index();
8847 return Smi::FromInt(index);
8848}
8849
8850
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008851// Return property value from named interceptor.
8852// args[0]: object
8853// args[1]: property name
lrn@chromium.org303ada72010-10-27 09:33:13 +00008854static MaybeObject* Runtime_DebugNamedInterceptorPropertyValue(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008855 HandleScope scope;
8856 ASSERT(args.length() == 2);
8857 CONVERT_ARG_CHECKED(JSObject, obj, 0);
8858 RUNTIME_ASSERT(obj->HasNamedInterceptor());
8859 CONVERT_ARG_CHECKED(String, name, 1);
8860
8861 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008862 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008863}
8864
8865
8866// Return element value from indexed interceptor.
8867// args[0]: object
8868// args[1]: index
lrn@chromium.org303ada72010-10-27 09:33:13 +00008869static MaybeObject* Runtime_DebugIndexedInterceptorElementValue(
8870 Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008871 HandleScope scope;
8872 ASSERT(args.length() == 2);
8873 CONVERT_ARG_CHECKED(JSObject, obj, 0);
8874 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
8875 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
8876
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008877 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008878}
8879
8880
lrn@chromium.org303ada72010-10-27 09:33:13 +00008881static MaybeObject* Runtime_CheckExecutionState(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008882 ASSERT(args.length() >= 1);
8883 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +00008884 // Check that the break id is valid.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00008885 if (Debug::break_id() == 0 || break_id != Debug::break_id()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008886 return Top::Throw(Heap::illegal_execution_state_symbol());
8887 }
8888
8889 return Heap::true_value();
8890}
8891
8892
lrn@chromium.org303ada72010-10-27 09:33:13 +00008893static MaybeObject* Runtime_GetFrameCount(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008894 HandleScope scope;
8895 ASSERT(args.length() == 1);
8896
8897 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008898 Object* result;
8899 { MaybeObject* maybe_result = Runtime_CheckExecutionState(args);
8900 if (!maybe_result->ToObject(&result)) return maybe_result;
8901 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008902
8903 // Count all frames which are relevant to debugging stack trace.
8904 int n = 0;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00008905 StackFrame::Id id = Debug::break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00008906 if (id == StackFrame::NO_ID) {
8907 // If there is no JavaScript stack frame count is 0.
8908 return Smi::FromInt(0);
8909 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008910 for (JavaScriptFrameIterator it(id); !it.done(); it.Advance()) n++;
8911 return Smi::FromInt(n);
8912}
8913
8914
8915static const int kFrameDetailsFrameIdIndex = 0;
8916static const int kFrameDetailsReceiverIndex = 1;
8917static const int kFrameDetailsFunctionIndex = 2;
8918static const int kFrameDetailsArgumentCountIndex = 3;
8919static const int kFrameDetailsLocalCountIndex = 4;
8920static const int kFrameDetailsSourcePositionIndex = 5;
8921static const int kFrameDetailsConstructCallIndex = 6;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008922static const int kFrameDetailsAtReturnIndex = 7;
8923static const int kFrameDetailsDebuggerFrameIndex = 8;
8924static const int kFrameDetailsFirstDynamicIndex = 9;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008925
8926// Return an array with frame details
8927// args[0]: number: break id
8928// args[1]: number: frame index
8929//
8930// The array returned contains the following information:
8931// 0: Frame id
8932// 1: Receiver
8933// 2: Function
8934// 3: Argument count
8935// 4: Local count
8936// 5: Source position
8937// 6: Constructor call
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008938// 7: Is at return
8939// 8: Debugger frame
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008940// Arguments name, value
8941// Locals name, value
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008942// Return value if any
lrn@chromium.org303ada72010-10-27 09:33:13 +00008943static MaybeObject* Runtime_GetFrameDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008944 HandleScope scope;
8945 ASSERT(args.length() == 2);
8946
8947 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008948 Object* check;
8949 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
8950 if (!maybe_check->ToObject(&check)) return maybe_check;
8951 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008952 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
8953
8954 // Find the relevant frame with the requested index.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00008955 StackFrame::Id id = Debug::break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00008956 if (id == StackFrame::NO_ID) {
8957 // If there are no JavaScript stack frames return undefined.
8958 return Heap::undefined_value();
8959 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008960 int count = 0;
8961 JavaScriptFrameIterator it(id);
8962 for (; !it.done(); it.Advance()) {
8963 if (count == index) break;
8964 count++;
8965 }
8966 if (it.done()) return Heap::undefined_value();
8967
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008968 bool is_optimized_frame =
8969 it.frame()->code()->kind() == Code::OPTIMIZED_FUNCTION;
8970
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008971 // Traverse the saved contexts chain to find the active context for the
8972 // selected frame.
8973 SaveContext* save = Top::save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008974 while (save != NULL && !save->below(it.frame())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008975 save = save->prev();
8976 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008977 ASSERT(save != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008978
8979 // Get the frame id.
8980 Handle<Object> frame_id(WrapFrameId(it.frame()->id()));
8981
8982 // Find source position.
kasperl@chromium.org061ef742009-02-27 12:16:20 +00008983 int position = it.frame()->code()->SourcePosition(it.frame()->pc());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008984
8985 // Check for constructor frame.
8986 bool constructor = it.frame()->IsConstructor();
8987
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00008988 // Get scope info and read from it for local variable information.
8989 Handle<JSFunction> function(JSFunction::cast(it.frame()->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +00008990 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00008991 ScopeInfo<> info(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008992
8993 // Get the context.
8994 Handle<Context> context(Context::cast(it.frame()->context()));
8995
8996 // Get the locals names and values into a temporary array.
8997 //
8998 // TODO(1240907): Hide compiler-introduced stack variables
8999 // (e.g. .result)? For users of the debugger, they will probably be
9000 // confusing.
9001 Handle<FixedArray> locals = Factory::NewFixedArray(info.NumberOfLocals() * 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009002
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009003 // Fill in the names of the locals.
9004 for (int i = 0; i < info.NumberOfLocals(); i++) {
9005 locals->set(i * 2, *info.LocalName(i));
9006 }
9007
9008 // Fill in the values of the locals.
9009 for (int i = 0; i < info.NumberOfLocals(); i++) {
9010 if (is_optimized_frame) {
9011 // If we are inspecting an optimized frame use undefined as the
9012 // value for all locals.
9013 //
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009014 // TODO(1140): We should be able to get the correct values
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009015 // for locals in optimized frames.
9016 locals->set(i * 2 + 1, Heap::undefined_value());
9017 } else if (i < info.number_of_stack_slots()) {
9018 // Get the value from the stack.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009019 locals->set(i * 2 + 1, it.frame()->GetExpression(i));
9020 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009021 // Traverse the context chain to the function context as all local
9022 // variables stored in the context will be on the function context.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009023 Handle<String> name = info.LocalName(i);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009024 while (!context->is_function_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009025 context = Handle<Context>(context->previous());
9026 }
9027 ASSERT(context->is_function_context());
9028 locals->set(i * 2 + 1,
ager@chromium.orgb5737492010-07-15 09:29:43 +00009029 context->get(scope_info->ContextSlotIndex(*name, NULL)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009030 }
9031 }
9032
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009033 // Check whether this frame is positioned at return. If not top
9034 // frame or if the frame is optimized it cannot be at a return.
9035 bool at_return = false;
9036 if (!is_optimized_frame && index == 0) {
9037 at_return = Debug::IsBreakAtReturn(it.frame());
9038 }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009039
9040 // If positioned just before return find the value to be returned and add it
9041 // to the frame information.
9042 Handle<Object> return_value = Factory::undefined_value();
9043 if (at_return) {
9044 StackFrameIterator it2;
9045 Address internal_frame_sp = NULL;
9046 while (!it2.done()) {
9047 if (it2.frame()->is_internal()) {
9048 internal_frame_sp = it2.frame()->sp();
9049 } else {
9050 if (it2.frame()->is_java_script()) {
9051 if (it2.frame()->id() == it.frame()->id()) {
9052 // The internal frame just before the JavaScript frame contains the
9053 // value to return on top. A debug break at return will create an
9054 // internal frame to store the return value (eax/rax/r0) before
9055 // entering the debug break exit frame.
9056 if (internal_frame_sp != NULL) {
9057 return_value =
9058 Handle<Object>(Memory::Object_at(internal_frame_sp));
9059 break;
9060 }
9061 }
9062 }
9063
9064 // Indicate that the previous frame was not an internal frame.
9065 internal_frame_sp = NULL;
9066 }
9067 it2.Advance();
9068 }
9069 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009070
9071 // Now advance to the arguments adapter frame (if any). It contains all
9072 // the provided parameters whereas the function frame always have the number
9073 // of arguments matching the functions parameters. The rest of the
9074 // information (except for what is collected above) is the same.
9075 it.AdvanceToArgumentsFrame();
9076
9077 // Find the number of arguments to fill. At least fill the number of
9078 // parameters for the function and fill more if more parameters are provided.
9079 int argument_count = info.number_of_parameters();
9080 if (argument_count < it.frame()->GetProvidedParametersCount()) {
9081 argument_count = it.frame()->GetProvidedParametersCount();
9082 }
9083
9084 // Calculate the size of the result.
9085 int details_size = kFrameDetailsFirstDynamicIndex +
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009086 2 * (argument_count + info.NumberOfLocals()) +
9087 (at_return ? 1 : 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009088 Handle<FixedArray> details = Factory::NewFixedArray(details_size);
9089
9090 // Add the frame id.
9091 details->set(kFrameDetailsFrameIdIndex, *frame_id);
9092
9093 // Add the function (same as in function frame).
9094 details->set(kFrameDetailsFunctionIndex, it.frame()->function());
9095
9096 // Add the arguments count.
9097 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
9098
9099 // Add the locals count
9100 details->set(kFrameDetailsLocalCountIndex,
9101 Smi::FromInt(info.NumberOfLocals()));
9102
9103 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +00009104 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009105 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
9106 } else {
9107 details->set(kFrameDetailsSourcePositionIndex, Heap::undefined_value());
9108 }
9109
9110 // Add the constructor information.
9111 details->set(kFrameDetailsConstructCallIndex, Heap::ToBoolean(constructor));
9112
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009113 // Add the at return information.
9114 details->set(kFrameDetailsAtReturnIndex, Heap::ToBoolean(at_return));
9115
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009116 // Add information on whether this frame is invoked in the debugger context.
9117 details->set(kFrameDetailsDebuggerFrameIndex,
9118 Heap::ToBoolean(*save->context() == *Debug::debug_context()));
9119
9120 // Fill the dynamic part.
9121 int details_index = kFrameDetailsFirstDynamicIndex;
9122
9123 // Add arguments name and value.
9124 for (int i = 0; i < argument_count; i++) {
9125 // Name of the argument.
9126 if (i < info.number_of_parameters()) {
9127 details->set(details_index++, *info.parameter_name(i));
9128 } else {
9129 details->set(details_index++, Heap::undefined_value());
9130 }
9131
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009132 // Parameter value. If we are inspecting an optimized frame, use
9133 // undefined as the value.
9134 //
9135 // TODO(3141533): We should be able to get the actual parameter
9136 // value for optimized frames.
9137 if (!is_optimized_frame &&
9138 (i < it.frame()->GetProvidedParametersCount())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009139 details->set(details_index++, it.frame()->GetParameter(i));
9140 } else {
9141 details->set(details_index++, Heap::undefined_value());
9142 }
9143 }
9144
9145 // Add locals name and value from the temporary copy from the function frame.
9146 for (int i = 0; i < info.NumberOfLocals() * 2; i++) {
9147 details->set(details_index++, locals->get(i));
9148 }
9149
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009150 // Add the value being returned.
9151 if (at_return) {
9152 details->set(details_index++, *return_value);
9153 }
9154
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009155 // Add the receiver (same as in function frame).
9156 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
9157 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
9158 Handle<Object> receiver(it.frame()->receiver());
9159 if (!receiver->IsJSObject()) {
9160 // If the receiver is NOT a JSObject we have hit an optimization
9161 // where a value object is not converted into a wrapped JS objects.
9162 // To hide this optimization from the debugger, we wrap the receiver
9163 // by creating correct wrapper object based on the calling frame's
9164 // global context.
9165 it.Advance();
9166 Handle<Context> calling_frames_global_context(
9167 Context::cast(Context::cast(it.frame()->context())->global_context()));
9168 receiver = Factory::ToObject(receiver, calling_frames_global_context);
9169 }
9170 details->set(kFrameDetailsReceiverIndex, *receiver);
9171
9172 ASSERT_EQ(details_size, details_index);
9173 return *Factory::NewJSArrayWithElements(details);
9174}
9175
9176
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009177// Copy all the context locals into an object used to materialize a scope.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009178static bool CopyContextLocalsToScopeObject(
ager@chromium.orgb5737492010-07-15 09:29:43 +00009179 Handle<SerializedScopeInfo> serialized_scope_info,
9180 ScopeInfo<>& scope_info,
9181 Handle<Context> context,
9182 Handle<JSObject> scope_object) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009183 // Fill all context locals to the context extension.
9184 for (int i = Context::MIN_CONTEXT_SLOTS;
9185 i < scope_info.number_of_context_slots();
9186 i++) {
ager@chromium.orgb5737492010-07-15 09:29:43 +00009187 int context_index = serialized_scope_info->ContextSlotIndex(
9188 *scope_info.context_slot_name(i), NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009189
9190 // Don't include the arguments shadow (.arguments) context variable.
9191 if (*scope_info.context_slot_name(i) != Heap::arguments_shadow_symbol()) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009192 RETURN_IF_EMPTY_HANDLE_VALUE(
9193 SetProperty(scope_object,
9194 scope_info.context_slot_name(i),
9195 Handle<Object>(context->get(context_index)), NONE),
9196 false);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009197 }
9198 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009199
9200 return true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009201}
9202
9203
9204// Create a plain JSObject which materializes the local scope for the specified
9205// frame.
9206static Handle<JSObject> MaterializeLocalScope(JavaScriptFrame* frame) {
9207 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009208 Handle<SharedFunctionInfo> shared(function->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +00009209 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
9210 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009211
9212 // Allocate and initialize a JSObject with all the arguments, stack locals
9213 // heap locals and extension properties of the debugged function.
9214 Handle<JSObject> local_scope = Factory::NewJSObject(Top::object_function());
9215
9216 // First fill all parameters.
9217 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009218 RETURN_IF_EMPTY_HANDLE_VALUE(
9219 SetProperty(local_scope,
9220 scope_info.parameter_name(i),
9221 Handle<Object>(frame->GetParameter(i)), NONE),
9222 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009223 }
9224
9225 // Second fill all stack locals.
9226 for (int i = 0; i < scope_info.number_of_stack_slots(); i++) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009227 RETURN_IF_EMPTY_HANDLE_VALUE(
9228 SetProperty(local_scope,
9229 scope_info.stack_slot_name(i),
9230 Handle<Object>(frame->GetExpression(i)), NONE),
9231 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009232 }
9233
9234 // Third fill all context locals.
9235 Handle<Context> frame_context(Context::cast(frame->context()));
9236 Handle<Context> function_context(frame_context->fcontext());
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009237 if (!CopyContextLocalsToScopeObject(serialized_scope_info, scope_info,
9238 function_context, local_scope)) {
9239 return Handle<JSObject>();
9240 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009241
9242 // Finally copy any properties from the function context extension. This will
9243 // be variables introduced by eval.
9244 if (function_context->closure() == *function) {
9245 if (function_context->has_extension() &&
9246 !function_context->IsGlobalContext()) {
9247 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009248 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009249 for (int i = 0; i < keys->length(); i++) {
9250 // Names of variables introduced by eval are strings.
9251 ASSERT(keys->get(i)->IsString());
9252 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009253 RETURN_IF_EMPTY_HANDLE_VALUE(
9254 SetProperty(local_scope, key, GetProperty(ext, key), NONE),
9255 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009256 }
9257 }
9258 }
9259 return local_scope;
9260}
9261
9262
9263// Create a plain JSObject which materializes the closure content for the
9264// context.
9265static Handle<JSObject> MaterializeClosure(Handle<Context> context) {
9266 ASSERT(context->is_function_context());
9267
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009268 Handle<SharedFunctionInfo> shared(context->closure()->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +00009269 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
9270 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009271
9272 // Allocate and initialize a JSObject with all the content of theis function
9273 // closure.
9274 Handle<JSObject> closure_scope = Factory::NewJSObject(Top::object_function());
9275
9276 // Check whether the arguments shadow object exists.
9277 int arguments_shadow_index =
ager@chromium.orgb5737492010-07-15 09:29:43 +00009278 shared->scope_info()->ContextSlotIndex(Heap::arguments_shadow_symbol(),
9279 NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009280 if (arguments_shadow_index >= 0) {
9281 // In this case all the arguments are available in the arguments shadow
9282 // object.
9283 Handle<JSObject> arguments_shadow(
9284 JSObject::cast(context->get(arguments_shadow_index)));
9285 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009286 // We don't expect exception-throwing getters on the arguments shadow.
9287 Object* element = arguments_shadow->GetElement(i)->ToObjectUnchecked();
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009288 RETURN_IF_EMPTY_HANDLE_VALUE(
9289 SetProperty(closure_scope,
9290 scope_info.parameter_name(i),
9291 Handle<Object>(element),
9292 NONE),
9293 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009294 }
9295 }
9296
9297 // Fill all context locals to the context extension.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009298 if (!CopyContextLocalsToScopeObject(serialized_scope_info, scope_info,
9299 context, closure_scope)) {
9300 return Handle<JSObject>();
9301 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009302
9303 // Finally copy any properties from the function context extension. This will
9304 // be variables introduced by eval.
9305 if (context->has_extension()) {
9306 Handle<JSObject> ext(JSObject::cast(context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009307 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009308 for (int i = 0; i < keys->length(); i++) {
9309 // Names of variables introduced by eval are strings.
9310 ASSERT(keys->get(i)->IsString());
9311 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009312 RETURN_IF_EMPTY_HANDLE_VALUE(
9313 SetProperty(closure_scope, key, GetProperty(ext, key), NONE),
9314 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009315 }
9316 }
9317
9318 return closure_scope;
9319}
9320
9321
9322// Iterate over the actual scopes visible from a stack frame. All scopes are
9323// backed by an actual context except the local scope, which is inserted
9324// "artifically" in the context chain.
9325class ScopeIterator {
9326 public:
9327 enum ScopeType {
9328 ScopeTypeGlobal = 0,
9329 ScopeTypeLocal,
9330 ScopeTypeWith,
ager@chromium.orga1645e22009-09-09 19:27:10 +00009331 ScopeTypeClosure,
9332 // Every catch block contains an implicit with block (its parameter is
9333 // a JSContextExtensionObject) that extends current scope with a variable
9334 // holding exception object. Such with blocks are treated as scopes of their
9335 // own type.
9336 ScopeTypeCatch
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009337 };
9338
9339 explicit ScopeIterator(JavaScriptFrame* frame)
9340 : frame_(frame),
9341 function_(JSFunction::cast(frame->function())),
9342 context_(Context::cast(frame->context())),
9343 local_done_(false),
9344 at_local_(false) {
9345
9346 // Check whether the first scope is actually a local scope.
9347 if (context_->IsGlobalContext()) {
9348 // If there is a stack slot for .result then this local scope has been
9349 // created for evaluating top level code and it is not a real local scope.
9350 // Checking for the existence of .result seems fragile, but the scope info
9351 // saved with the code object does not otherwise have that information.
ager@chromium.orgb5737492010-07-15 09:29:43 +00009352 int index = function_->shared()->scope_info()->
9353 StackSlotIndex(Heap::result_symbol());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009354 at_local_ = index < 0;
9355 } else if (context_->is_function_context()) {
9356 at_local_ = true;
9357 }
9358 }
9359
9360 // More scopes?
9361 bool Done() { return context_.is_null(); }
9362
9363 // Move to the next scope.
9364 void Next() {
9365 // If at a local scope mark the local scope as passed.
9366 if (at_local_) {
9367 at_local_ = false;
9368 local_done_ = true;
9369
9370 // If the current context is not associated with the local scope the
9371 // current context is the next real scope, so don't move to the next
9372 // context in this case.
9373 if (context_->closure() != *function_) {
9374 return;
9375 }
9376 }
9377
9378 // The global scope is always the last in the chain.
9379 if (context_->IsGlobalContext()) {
9380 context_ = Handle<Context>();
9381 return;
9382 }
9383
9384 // Move to the next context.
9385 if (context_->is_function_context()) {
9386 context_ = Handle<Context>(Context::cast(context_->closure()->context()));
9387 } else {
9388 context_ = Handle<Context>(context_->previous());
9389 }
9390
9391 // If passing the local scope indicate that the current scope is now the
9392 // local scope.
9393 if (!local_done_ &&
9394 (context_->IsGlobalContext() || (context_->is_function_context()))) {
9395 at_local_ = true;
9396 }
9397 }
9398
9399 // Return the type of the current scope.
9400 int Type() {
9401 if (at_local_) {
9402 return ScopeTypeLocal;
9403 }
9404 if (context_->IsGlobalContext()) {
9405 ASSERT(context_->global()->IsGlobalObject());
9406 return ScopeTypeGlobal;
9407 }
9408 if (context_->is_function_context()) {
9409 return ScopeTypeClosure;
9410 }
9411 ASSERT(context_->has_extension());
ager@chromium.orga1645e22009-09-09 19:27:10 +00009412 // Current scope is either an explicit with statement or a with statement
9413 // implicitely generated for a catch block.
9414 // If the extension object here is a JSContextExtensionObject then
9415 // current with statement is one frome a catch block otherwise it's a
9416 // regular with statement.
9417 if (context_->extension()->IsJSContextExtensionObject()) {
9418 return ScopeTypeCatch;
9419 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009420 return ScopeTypeWith;
9421 }
9422
9423 // Return the JavaScript object with the content of the current scope.
9424 Handle<JSObject> ScopeObject() {
9425 switch (Type()) {
9426 case ScopeIterator::ScopeTypeGlobal:
9427 return Handle<JSObject>(CurrentContext()->global());
9428 break;
9429 case ScopeIterator::ScopeTypeLocal:
9430 // Materialize the content of the local scope into a JSObject.
9431 return MaterializeLocalScope(frame_);
9432 break;
9433 case ScopeIterator::ScopeTypeWith:
ager@chromium.orga1645e22009-09-09 19:27:10 +00009434 case ScopeIterator::ScopeTypeCatch:
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009435 // Return the with object.
9436 return Handle<JSObject>(CurrentContext()->extension());
9437 break;
9438 case ScopeIterator::ScopeTypeClosure:
9439 // Materialize the content of the closure scope into a JSObject.
9440 return MaterializeClosure(CurrentContext());
9441 break;
9442 }
9443 UNREACHABLE();
9444 return Handle<JSObject>();
9445 }
9446
9447 // Return the context for this scope. For the local context there might not
9448 // be an actual context.
9449 Handle<Context> CurrentContext() {
9450 if (at_local_ && context_->closure() != *function_) {
9451 return Handle<Context>();
9452 }
9453 return context_;
9454 }
9455
9456#ifdef DEBUG
9457 // Debug print of the content of the current scope.
9458 void DebugPrint() {
9459 switch (Type()) {
9460 case ScopeIterator::ScopeTypeGlobal:
9461 PrintF("Global:\n");
9462 CurrentContext()->Print();
9463 break;
9464
9465 case ScopeIterator::ScopeTypeLocal: {
9466 PrintF("Local:\n");
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009467 ScopeInfo<> scope_info(function_->shared()->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009468 scope_info.Print();
9469 if (!CurrentContext().is_null()) {
9470 CurrentContext()->Print();
9471 if (CurrentContext()->has_extension()) {
9472 Handle<JSObject> extension =
9473 Handle<JSObject>(CurrentContext()->extension());
9474 if (extension->IsJSContextExtensionObject()) {
9475 extension->Print();
9476 }
9477 }
9478 }
9479 break;
9480 }
9481
9482 case ScopeIterator::ScopeTypeWith: {
9483 PrintF("With:\n");
9484 Handle<JSObject> extension =
9485 Handle<JSObject>(CurrentContext()->extension());
9486 extension->Print();
9487 break;
9488 }
9489
ager@chromium.orga1645e22009-09-09 19:27:10 +00009490 case ScopeIterator::ScopeTypeCatch: {
9491 PrintF("Catch:\n");
9492 Handle<JSObject> extension =
9493 Handle<JSObject>(CurrentContext()->extension());
9494 extension->Print();
9495 break;
9496 }
9497
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009498 case ScopeIterator::ScopeTypeClosure: {
9499 PrintF("Closure:\n");
9500 CurrentContext()->Print();
9501 if (CurrentContext()->has_extension()) {
9502 Handle<JSObject> extension =
9503 Handle<JSObject>(CurrentContext()->extension());
9504 if (extension->IsJSContextExtensionObject()) {
9505 extension->Print();
9506 }
9507 }
9508 break;
9509 }
9510
9511 default:
9512 UNREACHABLE();
9513 }
9514 PrintF("\n");
9515 }
9516#endif
9517
9518 private:
9519 JavaScriptFrame* frame_;
9520 Handle<JSFunction> function_;
9521 Handle<Context> context_;
9522 bool local_done_;
9523 bool at_local_;
9524
9525 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
9526};
9527
9528
lrn@chromium.org303ada72010-10-27 09:33:13 +00009529static MaybeObject* Runtime_GetScopeCount(Arguments args) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009530 HandleScope scope;
9531 ASSERT(args.length() == 2);
9532
9533 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009534 Object* check;
9535 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
9536 if (!maybe_check->ToObject(&check)) return maybe_check;
9537 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009538 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
9539
9540 // Get the frame where the debugging is performed.
9541 StackFrame::Id id = UnwrapFrameId(wrapped_id);
9542 JavaScriptFrameIterator it(id);
9543 JavaScriptFrame* frame = it.frame();
9544
9545 // Count the visible scopes.
9546 int n = 0;
9547 for (ScopeIterator it(frame); !it.Done(); it.Next()) {
9548 n++;
9549 }
9550
9551 return Smi::FromInt(n);
9552}
9553
9554
9555static const int kScopeDetailsTypeIndex = 0;
9556static const int kScopeDetailsObjectIndex = 1;
9557static const int kScopeDetailsSize = 2;
9558
9559// Return an array with scope details
9560// args[0]: number: break id
9561// args[1]: number: frame index
9562// args[2]: number: scope index
9563//
9564// The array returned contains the following information:
9565// 0: Scope type
9566// 1: Scope object
lrn@chromium.org303ada72010-10-27 09:33:13 +00009567static MaybeObject* Runtime_GetScopeDetails(Arguments args) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009568 HandleScope scope;
9569 ASSERT(args.length() == 3);
9570
9571 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009572 Object* check;
9573 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
9574 if (!maybe_check->ToObject(&check)) return maybe_check;
9575 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009576 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
9577 CONVERT_NUMBER_CHECKED(int, index, Int32, args[2]);
9578
9579 // Get the frame where the debugging is performed.
9580 StackFrame::Id id = UnwrapFrameId(wrapped_id);
9581 JavaScriptFrameIterator frame_it(id);
9582 JavaScriptFrame* frame = frame_it.frame();
9583
9584 // Find the requested scope.
9585 int n = 0;
9586 ScopeIterator it(frame);
9587 for (; !it.Done() && n < index; it.Next()) {
9588 n++;
9589 }
9590 if (it.Done()) {
9591 return Heap::undefined_value();
9592 }
9593
9594 // Calculate the size of the result.
9595 int details_size = kScopeDetailsSize;
9596 Handle<FixedArray> details = Factory::NewFixedArray(details_size);
9597
9598 // Fill in scope details.
9599 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00009600 Handle<JSObject> scope_object = it.ScopeObject();
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009601 RETURN_IF_EMPTY_HANDLE(scope_object);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00009602 details->set(kScopeDetailsObjectIndex, *scope_object);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009603
9604 return *Factory::NewJSArrayWithElements(details);
9605}
9606
9607
lrn@chromium.org303ada72010-10-27 09:33:13 +00009608static MaybeObject* Runtime_DebugPrintScopes(Arguments args) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009609 HandleScope scope;
9610 ASSERT(args.length() == 0);
9611
9612#ifdef DEBUG
9613 // Print the scopes for the top frame.
9614 StackFrameLocator locator;
9615 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
9616 for (ScopeIterator it(frame); !it.Done(); it.Next()) {
9617 it.DebugPrint();
9618 }
9619#endif
9620 return Heap::undefined_value();
9621}
9622
9623
lrn@chromium.org303ada72010-10-27 09:33:13 +00009624static MaybeObject* Runtime_GetThreadCount(Arguments args) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009625 HandleScope scope;
9626 ASSERT(args.length() == 1);
9627
9628 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009629 Object* result;
9630 { MaybeObject* maybe_result = Runtime_CheckExecutionState(args);
9631 if (!maybe_result->ToObject(&result)) return maybe_result;
9632 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009633
9634 // Count all archived V8 threads.
9635 int n = 0;
9636 for (ThreadState* thread = ThreadState::FirstInUse();
9637 thread != NULL;
9638 thread = thread->Next()) {
9639 n++;
9640 }
9641
9642 // Total number of threads is current thread and archived threads.
9643 return Smi::FromInt(n + 1);
9644}
9645
9646
9647static const int kThreadDetailsCurrentThreadIndex = 0;
9648static const int kThreadDetailsThreadIdIndex = 1;
9649static const int kThreadDetailsSize = 2;
9650
9651// Return an array with thread details
9652// args[0]: number: break id
9653// args[1]: number: thread index
9654//
9655// The array returned contains the following information:
9656// 0: Is current thread?
9657// 1: Thread id
lrn@chromium.org303ada72010-10-27 09:33:13 +00009658static MaybeObject* Runtime_GetThreadDetails(Arguments args) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009659 HandleScope scope;
9660 ASSERT(args.length() == 2);
9661
9662 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009663 Object* check;
9664 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
9665 if (!maybe_check->ToObject(&check)) return maybe_check;
9666 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009667 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
9668
9669 // Allocate array for result.
9670 Handle<FixedArray> details = Factory::NewFixedArray(kThreadDetailsSize);
9671
9672 // Thread index 0 is current thread.
9673 if (index == 0) {
9674 // Fill the details.
9675 details->set(kThreadDetailsCurrentThreadIndex, Heap::true_value());
9676 details->set(kThreadDetailsThreadIdIndex,
9677 Smi::FromInt(ThreadManager::CurrentId()));
9678 } else {
9679 // Find the thread with the requested index.
9680 int n = 1;
9681 ThreadState* thread = ThreadState::FirstInUse();
9682 while (index != n && thread != NULL) {
9683 thread = thread->Next();
9684 n++;
9685 }
9686 if (thread == NULL) {
9687 return Heap::undefined_value();
9688 }
9689
9690 // Fill the details.
9691 details->set(kThreadDetailsCurrentThreadIndex, Heap::false_value());
9692 details->set(kThreadDetailsThreadIdIndex, Smi::FromInt(thread->id()));
9693 }
9694
9695 // Convert to JS array and return.
9696 return *Factory::NewJSArrayWithElements(details);
9697}
9698
9699
whesse@chromium.orge90029b2010-08-02 11:52:17 +00009700// Sets the disable break state
9701// args[0]: disable break state
lrn@chromium.org303ada72010-10-27 09:33:13 +00009702static MaybeObject* Runtime_SetDisableBreak(Arguments args) {
whesse@chromium.orge90029b2010-08-02 11:52:17 +00009703 HandleScope scope;
9704 ASSERT(args.length() == 1);
9705 CONVERT_BOOLEAN_CHECKED(disable_break, args[0]);
9706 Debug::set_disable_break(disable_break);
9707 return Heap::undefined_value();
9708}
9709
9710
lrn@chromium.org303ada72010-10-27 09:33:13 +00009711static MaybeObject* Runtime_GetBreakLocations(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009712 HandleScope scope;
9713 ASSERT(args.length() == 1);
9714
ager@chromium.org5aa501c2009-06-23 07:57:28 +00009715 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
9716 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009717 // Find the number of break points
9718 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
9719 if (break_locations->IsUndefined()) return Heap::undefined_value();
9720 // Return array as JS array
9721 return *Factory::NewJSArrayWithElements(
9722 Handle<FixedArray>::cast(break_locations));
9723}
9724
9725
9726// Set a break point in a function
9727// args[0]: function
9728// args[1]: number: break source position (within the function source)
9729// args[2]: number: break point object
lrn@chromium.org303ada72010-10-27 09:33:13 +00009730static MaybeObject* Runtime_SetFunctionBreakPoint(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009731 HandleScope scope;
9732 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00009733 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
9734 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009735 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
9736 RUNTIME_ASSERT(source_position >= 0);
9737 Handle<Object> break_point_object_arg = args.at<Object>(2);
9738
9739 // Set break point.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00009740 Debug::SetBreakPoint(shared, break_point_object_arg, &source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009741
lrn@chromium.org32d961d2010-06-30 09:09:34 +00009742 return Smi::FromInt(source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009743}
9744
9745
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00009746Object* Runtime::FindSharedFunctionInfoInScript(Handle<Script> script,
9747 int position) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009748 // Iterate the heap looking for SharedFunctionInfo generated from the
9749 // script. The inner most SharedFunctionInfo containing the source position
9750 // for the requested break point is found.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009751 // NOTE: This might require several heap iterations. If the SharedFunctionInfo
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009752 // which is found is not compiled it is compiled and the heap is iterated
9753 // again as the compilation might create inner functions from the newly
9754 // compiled function and the actual requested break point might be in one of
9755 // these functions.
9756 bool done = false;
9757 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +00009758 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009759 Handle<SharedFunctionInfo> target;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009760 while (!done) {
9761 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009762 for (HeapObject* obj = iterator.next();
9763 obj != NULL; obj = iterator.next()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009764 if (obj->IsSharedFunctionInfo()) {
9765 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
9766 if (shared->script() == *script) {
9767 // If the SharedFunctionInfo found has the requested script data and
9768 // contains the source position it is a candidate.
9769 int start_position = shared->function_token_position();
ager@chromium.org236ad962008-09-25 09:45:57 +00009770 if (start_position == RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009771 start_position = shared->start_position();
9772 }
9773 if (start_position <= position &&
9774 position <= shared->end_position()) {
ager@chromium.org32912102009-01-16 10:38:43 +00009775 // If there is no candidate or this function is within the current
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009776 // candidate this is the new candidate.
9777 if (target.is_null()) {
9778 target_start_position = start_position;
9779 target = shared;
9780 } else {
ager@chromium.orga1645e22009-09-09 19:27:10 +00009781 if (target_start_position == start_position &&
9782 shared->end_position() == target->end_position()) {
9783 // If a top-level function contain only one function
9784 // declartion the source for the top-level and the function is
9785 // the same. In that case prefer the non top-level function.
9786 if (!shared->is_toplevel()) {
9787 target_start_position = start_position;
9788 target = shared;
9789 }
9790 } else if (target_start_position <= start_position &&
9791 shared->end_position() <= target->end_position()) {
9792 // This containment check includes equality as a function inside
9793 // a top-level function can share either start or end position
9794 // with the top-level function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009795 target_start_position = start_position;
9796 target = shared;
9797 }
9798 }
9799 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009800 }
9801 }
9802 }
9803
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009804 if (target.is_null()) {
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00009805 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009806 }
9807
9808 // If the candidate found is compiled we are done. NOTE: when lazy
9809 // compilation of inner functions is introduced some additional checking
9810 // needs to be done here to compile inner functions.
9811 done = target->is_compiled();
9812 if (!done) {
9813 // If the candidate is not compiled compile it to reveal any inner
9814 // functions which might contain the requested source position.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009815 CompileLazyShared(target, KEEP_EXCEPTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009816 }
9817 }
9818
9819 return *target;
9820}
9821
9822
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00009823// Changes the state of a break point in a script and returns source position
9824// where break point was set. NOTE: Regarding performance see the NOTE for
9825// GetScriptFromScriptData.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009826// args[0]: script to set break point in
9827// args[1]: number: break source position (within the script source)
9828// args[2]: number: break point object
lrn@chromium.org303ada72010-10-27 09:33:13 +00009829static MaybeObject* Runtime_SetScriptBreakPoint(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009830 HandleScope scope;
9831 ASSERT(args.length() == 3);
9832 CONVERT_ARG_CHECKED(JSValue, wrapper, 0);
9833 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
9834 RUNTIME_ASSERT(source_position >= 0);
9835 Handle<Object> break_point_object_arg = args.at<Object>(2);
9836
9837 // Get the script from the script wrapper.
9838 RUNTIME_ASSERT(wrapper->value()->IsScript());
9839 Handle<Script> script(Script::cast(wrapper->value()));
9840
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00009841 Object* result = Runtime::FindSharedFunctionInfoInScript(
9842 script, source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009843 if (!result->IsUndefined()) {
9844 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
9845 // Find position within function. The script position might be before the
9846 // source position of the first function.
9847 int position;
9848 if (shared->start_position() > source_position) {
9849 position = 0;
9850 } else {
9851 position = source_position - shared->start_position();
9852 }
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00009853 Debug::SetBreakPoint(shared, break_point_object_arg, &position);
9854 position += shared->start_position();
9855 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009856 }
9857 return Heap::undefined_value();
9858}
9859
9860
9861// Clear a break point
9862// args[0]: number: break point object
lrn@chromium.org303ada72010-10-27 09:33:13 +00009863static MaybeObject* Runtime_ClearBreakPoint(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009864 HandleScope scope;
9865 ASSERT(args.length() == 1);
9866 Handle<Object> break_point_object_arg = args.at<Object>(0);
9867
9868 // Clear break point.
9869 Debug::ClearBreakPoint(break_point_object_arg);
9870
9871 return Heap::undefined_value();
9872}
9873
9874
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00009875// Change the state of break on exceptions.
9876// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
9877// args[1]: Boolean indicating on/off.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009878static MaybeObject* Runtime_ChangeBreakOnException(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009879 HandleScope scope;
9880 ASSERT(args.length() == 2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00009881 RUNTIME_ASSERT(args[0]->IsNumber());
9882 CONVERT_BOOLEAN_CHECKED(enable, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009883
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00009884 // If the number doesn't match an enum value, the ChangeBreakOnException
9885 // function will default to affecting caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009886 ExceptionBreakType type =
9887 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00009888 // Update break point state.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009889 Debug::ChangeBreakOnException(type, enable);
9890 return Heap::undefined_value();
9891}
9892
9893
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00009894// Returns the state of break on exceptions
9895// args[0]: boolean indicating uncaught exceptions
lrn@chromium.org303ada72010-10-27 09:33:13 +00009896static MaybeObject* Runtime_IsBreakOnException(Arguments args) {
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00009897 HandleScope scope;
9898 ASSERT(args.length() == 1);
9899 RUNTIME_ASSERT(args[0]->IsNumber());
9900
9901 ExceptionBreakType type =
9902 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
9903 bool result = Debug::IsBreakOnException(type);
9904 return Smi::FromInt(result);
9905}
9906
9907
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009908// Prepare for stepping
9909// args[0]: break id for checking execution state
9910// args[1]: step action from the enumeration StepAction
ager@chromium.orga1645e22009-09-09 19:27:10 +00009911// args[2]: number of times to perform the step, for step out it is the number
9912// of frames to step down.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009913static MaybeObject* Runtime_PrepareStep(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009914 HandleScope scope;
9915 ASSERT(args.length() == 3);
9916 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009917 Object* check;
9918 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
9919 if (!maybe_check->ToObject(&check)) return maybe_check;
9920 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009921 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
9922 return Top::Throw(Heap::illegal_argument_symbol());
9923 }
9924
9925 // Get the step action and check validity.
9926 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
9927 if (step_action != StepIn &&
9928 step_action != StepNext &&
9929 step_action != StepOut &&
9930 step_action != StepInMin &&
9931 step_action != StepMin) {
9932 return Top::Throw(Heap::illegal_argument_symbol());
9933 }
9934
9935 // Get the number of steps.
9936 int step_count = NumberToInt32(args[2]);
9937 if (step_count < 1) {
9938 return Top::Throw(Heap::illegal_argument_symbol());
9939 }
9940
ager@chromium.orga1645e22009-09-09 19:27:10 +00009941 // Clear all current stepping setup.
9942 Debug::ClearStepping();
9943
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009944 // Prepare step.
9945 Debug::PrepareStep(static_cast<StepAction>(step_action), step_count);
9946 return Heap::undefined_value();
9947}
9948
9949
9950// Clear all stepping set by PrepareStep.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009951static MaybeObject* Runtime_ClearStepping(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009952 HandleScope scope;
mads.s.ager31e71382008-08-13 09:32:07 +00009953 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009954 Debug::ClearStepping();
9955 return Heap::undefined_value();
9956}
9957
9958
9959// Creates a copy of the with context chain. The copy of the context chain is
9960// is linked to the function context supplied.
9961static Handle<Context> CopyWithContextChain(Handle<Context> context_chain,
9962 Handle<Context> function_context) {
9963 // At the bottom of the chain. Return the function context to link to.
9964 if (context_chain->is_function_context()) {
9965 return function_context;
9966 }
9967
9968 // Recursively copy the with contexts.
9969 Handle<Context> previous(context_chain->previous());
9970 Handle<JSObject> extension(JSObject::cast(context_chain->extension()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00009971 Handle<Context> context = CopyWithContextChain(function_context, previous);
9972 return Factory::NewWithContext(context,
9973 extension,
9974 context_chain->IsCatchContext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009975}
9976
9977
9978// Helper function to find or create the arguments object for
9979// Runtime_DebugEvaluate.
9980static Handle<Object> GetArgumentsObject(JavaScriptFrame* frame,
9981 Handle<JSFunction> function,
ager@chromium.orgb5737492010-07-15 09:29:43 +00009982 Handle<SerializedScopeInfo> scope_info,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009983 const ScopeInfo<>* sinfo,
9984 Handle<Context> function_context) {
9985 // Try to find the value of 'arguments' to pass as parameter. If it is not
9986 // found (that is the debugged function does not reference 'arguments' and
9987 // does not support eval) then create an 'arguments' object.
9988 int index;
9989 if (sinfo->number_of_stack_slots() > 0) {
ager@chromium.orgb5737492010-07-15 09:29:43 +00009990 index = scope_info->StackSlotIndex(Heap::arguments_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009991 if (index != -1) {
9992 return Handle<Object>(frame->GetExpression(index));
9993 }
9994 }
9995
9996 if (sinfo->number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
ager@chromium.orgb5737492010-07-15 09:29:43 +00009997 index = scope_info->ContextSlotIndex(Heap::arguments_symbol(), NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009998 if (index != -1) {
9999 return Handle<Object>(function_context->get(index));
10000 }
10001 }
10002
10003 const int length = frame->GetProvidedParametersCount();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000010004 Handle<JSObject> arguments = Factory::NewArgumentsObject(function, length);
10005 Handle<FixedArray> array = Factory::NewFixedArray(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010006
10007 AssertNoAllocation no_gc;
10008 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010009 for (int i = 0; i < length; i++) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010010 array->set(i, frame->GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010011 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000010012 arguments->set_elements(*array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010013 return arguments;
10014}
10015
10016
10017// Evaluate a piece of JavaScript in the context of a stack frame for
ager@chromium.org32912102009-01-16 10:38:43 +000010018// debugging. This is accomplished by creating a new context which in its
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010019// extension part has all the parameters and locals of the function on the
10020// stack frame. A function which calls eval with the code to evaluate is then
10021// compiled in this context and called in this context. As this context
10022// replaces the context of the function on the stack frame a new (empty)
10023// function is created as well to be used as the closure for the context.
10024// This function and the context acts as replacements for the function on the
10025// stack frame presenting the same view of the values of parameters and
10026// local variables as if the piece of JavaScript was evaluated at the point
10027// where the function on the stack frame is currently stopped.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010028static MaybeObject* Runtime_DebugEvaluate(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010029 HandleScope scope;
10030
10031 // Check the execution state and decode arguments frame and source to be
10032 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010033 ASSERT(args.length() == 5);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010034 Object* check_result;
10035 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(args);
10036 if (!maybe_check_result->ToObject(&check_result)) {
10037 return maybe_check_result;
10038 }
10039 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010040 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
10041 CONVERT_ARG_CHECKED(String, source, 2);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000010042 CONVERT_BOOLEAN_CHECKED(disable_break, args[3]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010043 Handle<Object> additional_context(args[4]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000010044
10045 // Handle the processing of break.
10046 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010047
10048 // Get the frame where the debugging is performed.
10049 StackFrame::Id id = UnwrapFrameId(wrapped_id);
10050 JavaScriptFrameIterator it(id);
10051 JavaScriptFrame* frame = it.frame();
10052 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +000010053 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010054 ScopeInfo<> sinfo(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010055
10056 // Traverse the saved contexts chain to find the active context for the
10057 // selected frame.
10058 SaveContext* save = Top::save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010059 while (save != NULL && !save->below(frame)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010060 save = save->prev();
10061 }
10062 ASSERT(save != NULL);
10063 SaveContext savex;
10064 Top::set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010065
10066 // Create the (empty) function replacing the function on the stack frame for
10067 // the purpose of evaluating in the context created below. It is important
10068 // that this function does not describe any parameters and local variables
10069 // in the context. If it does then this will cause problems with the lookup
10070 // in Context::Lookup, where context slots for parameters and local variables
10071 // are looked at before the extension object.
10072 Handle<JSFunction> go_between =
10073 Factory::NewFunction(Factory::empty_string(), Factory::undefined_value());
10074 go_between->set_context(function->context());
10075#ifdef DEBUG
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010076 ScopeInfo<> go_between_sinfo(go_between->shared()->scope_info());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010077 ASSERT(go_between_sinfo.number_of_parameters() == 0);
10078 ASSERT(go_between_sinfo.number_of_context_slots() == 0);
10079#endif
10080
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010081 // Materialize the content of the local scope into a JSObject.
10082 Handle<JSObject> local_scope = MaterializeLocalScope(frame);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010083 RETURN_IF_EMPTY_HANDLE(local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010084
10085 // Allocate a new context for the debug evaluation and set the extension
10086 // object build.
10087 Handle<Context> context =
10088 Factory::NewFunctionContext(Context::MIN_CONTEXT_SLOTS, go_between);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010089 context->set_extension(*local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010090 // Copy any with contexts present and chain them in front of this context.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010091 Handle<Context> frame_context(Context::cast(frame->context()));
10092 Handle<Context> function_context(frame_context->fcontext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010093 context = CopyWithContextChain(frame_context, context);
10094
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010095 if (additional_context->IsJSObject()) {
10096 context = Factory::NewWithContext(context,
10097 Handle<JSObject>::cast(additional_context), false);
10098 }
10099
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010100 // Wrap the evaluation statement in a new function compiled in the newly
10101 // created context. The function has one parameter which has to be called
10102 // 'arguments'. This it to have access to what would have been 'arguments' in
ager@chromium.org32912102009-01-16 10:38:43 +000010103 // the function being debugged.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010104 // function(arguments,__source__) {return eval(__source__);}
10105 static const char* source_str =
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000010106 "(function(arguments,__source__){return eval(__source__);})";
ager@chromium.orgc4c92722009-11-18 14:12:51 +000010107 static const int source_str_length = StrLength(source_str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010108 Handle<String> function_source =
10109 Factory::NewStringFromAscii(Vector<const char>(source_str,
10110 source_str_length));
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010111
10112 // Currently, the eval code will be executed in non-strict mode,
10113 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010114 Handle<SharedFunctionInfo> shared =
ager@chromium.org381abbb2009-02-25 13:23:22 +000010115 Compiler::CompileEval(function_source,
10116 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010117 context->IsGlobalContext(),
10118 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010119 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010120 Handle<JSFunction> compiled_function =
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010121 Factory::NewFunctionFromSharedFunctionInfo(shared, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010122
10123 // Invoke the result of the compilation to get the evaluation function.
10124 bool has_pending_exception;
10125 Handle<Object> receiver(frame->receiver());
10126 Handle<Object> evaluation_function =
10127 Execution::Call(compiled_function, receiver, 0, NULL,
10128 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000010129 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010130
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010131 Handle<Object> arguments = GetArgumentsObject(frame, function, scope_info,
10132 &sinfo, function_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010133
10134 // Invoke the evaluation function and return the result.
10135 const int argc = 2;
10136 Object** argv[argc] = { arguments.location(),
10137 Handle<Object>::cast(source).location() };
10138 Handle<Object> result =
10139 Execution::Call(Handle<JSFunction>::cast(evaluation_function), receiver,
10140 argc, argv, &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000010141 if (has_pending_exception) return Failure::Exception();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010142
10143 // Skip the global proxy as it has no properties and always delegates to the
10144 // real global object.
10145 if (result->IsJSGlobalProxy()) {
10146 result = Handle<JSObject>(JSObject::cast(result->GetPrototype()));
10147 }
10148
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010149 return *result;
10150}
10151
10152
lrn@chromium.org303ada72010-10-27 09:33:13 +000010153static MaybeObject* Runtime_DebugEvaluateGlobal(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010154 HandleScope scope;
10155
10156 // Check the execution state and decode arguments frame and source to be
10157 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010158 ASSERT(args.length() == 4);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010159 Object* check_result;
10160 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(args);
10161 if (!maybe_check_result->ToObject(&check_result)) {
10162 return maybe_check_result;
10163 }
10164 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010165 CONVERT_ARG_CHECKED(String, source, 1);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000010166 CONVERT_BOOLEAN_CHECKED(disable_break, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010167 Handle<Object> additional_context(args[3]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000010168
10169 // Handle the processing of break.
10170 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010171
10172 // Enter the top context from before the debugger was invoked.
10173 SaveContext save;
10174 SaveContext* top = &save;
10175 while (top != NULL && *top->context() == *Debug::debug_context()) {
10176 top = top->prev();
10177 }
10178 if (top != NULL) {
10179 Top::set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010180 }
10181
10182 // Get the global context now set to the top context from before the
10183 // debugger was invoked.
10184 Handle<Context> context = Top::global_context();
10185
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010186 bool is_global = true;
10187
10188 if (additional_context->IsJSObject()) {
10189 // Create a function context first, than put 'with' context on top of it.
10190 Handle<JSFunction> go_between = Factory::NewFunction(
10191 Factory::empty_string(), Factory::undefined_value());
10192 go_between->set_context(*context);
10193 context =
10194 Factory::NewFunctionContext(Context::MIN_CONTEXT_SLOTS, go_between);
10195 context->set_extension(JSObject::cast(*additional_context));
10196 is_global = false;
10197 }
10198
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010199 // Compile the source to be evaluated.
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010200 // Currently, the eval code will be executed in non-strict mode,
10201 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010202 Handle<SharedFunctionInfo> shared =
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010203 Compiler::CompileEval(source, context, is_global, kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010204 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010205 Handle<JSFunction> compiled_function =
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010206 Handle<JSFunction>(Factory::NewFunctionFromSharedFunctionInfo(shared,
10207 context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010208
10209 // Invoke the result of the compilation to get the evaluation function.
10210 bool has_pending_exception;
10211 Handle<Object> receiver = Top::global();
10212 Handle<Object> result =
10213 Execution::Call(compiled_function, receiver, 0, NULL,
10214 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000010215 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010216 return *result;
10217}
10218
10219
lrn@chromium.org303ada72010-10-27 09:33:13 +000010220static MaybeObject* Runtime_DebugGetLoadedScripts(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010221 HandleScope scope;
mads.s.ager31e71382008-08-13 09:32:07 +000010222 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010223
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010224 // Fill the script objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +000010225 Handle<FixedArray> instances = Debug::GetLoadedScripts();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010226
10227 // Convert the script objects to proper JS objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +000010228 for (int i = 0; i < instances->length(); i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +000010229 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
10230 // Get the script wrapper in a local handle before calling GetScriptWrapper,
10231 // because using
10232 // instances->set(i, *GetScriptWrapper(script))
10233 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
10234 // already have deferenced the instances handle.
10235 Handle<JSValue> wrapper = GetScriptWrapper(script);
10236 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010237 }
10238
10239 // Return result as a JS array.
10240 Handle<JSObject> result = Factory::NewJSObject(Top::array_function());
10241 Handle<JSArray>::cast(result)->SetContent(*instances);
10242 return *result;
10243}
10244
10245
10246// Helper function used by Runtime_DebugReferencedBy below.
10247static int DebugReferencedBy(JSObject* target,
10248 Object* instance_filter, int max_references,
10249 FixedArray* instances, int instances_size,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010250 JSFunction* arguments_function) {
10251 NoHandleAllocation ha;
10252 AssertNoAllocation no_alloc;
10253
10254 // Iterate the heap.
10255 int count = 0;
10256 JSObject* last = NULL;
10257 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010258 HeapObject* heap_obj = NULL;
10259 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010260 (max_references == 0 || count < max_references)) {
10261 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010262 if (heap_obj->IsJSObject()) {
10263 // Skip context extension objects and argument arrays as these are
10264 // checked in the context of functions using them.
10265 JSObject* obj = JSObject::cast(heap_obj);
iposva@chromium.org245aa852009-02-10 00:49:54 +000010266 if (obj->IsJSContextExtensionObject() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010267 obj->map()->constructor() == arguments_function) {
10268 continue;
10269 }
10270
10271 // Check if the JS object has a reference to the object looked for.
10272 if (obj->ReferencesObject(target)) {
10273 // Check instance filter if supplied. This is normally used to avoid
10274 // references from mirror objects (see Runtime_IsInPrototypeChain).
10275 if (!instance_filter->IsUndefined()) {
10276 Object* V = obj;
10277 while (true) {
10278 Object* prototype = V->GetPrototype();
10279 if (prototype->IsNull()) {
10280 break;
10281 }
10282 if (instance_filter == prototype) {
10283 obj = NULL; // Don't add this object.
10284 break;
10285 }
10286 V = prototype;
10287 }
10288 }
10289
10290 if (obj != NULL) {
10291 // Valid reference found add to instance array if supplied an update
10292 // count.
10293 if (instances != NULL && count < instances_size) {
10294 instances->set(count, obj);
10295 }
10296 last = obj;
10297 count++;
10298 }
10299 }
10300 }
10301 }
10302
10303 // Check for circular reference only. This can happen when the object is only
10304 // referenced from mirrors and has a circular reference in which case the
10305 // object is not really alive and would have been garbage collected if not
10306 // referenced from the mirror.
10307 if (count == 1 && last == target) {
10308 count = 0;
10309 }
10310
10311 // Return the number of referencing objects found.
10312 return count;
10313}
10314
10315
10316// Scan the heap for objects with direct references to an object
10317// args[0]: the object to find references to
10318// args[1]: constructor function for instances to exclude (Mirror)
10319// args[2]: the the maximum number of objects to return
lrn@chromium.org303ada72010-10-27 09:33:13 +000010320static MaybeObject* Runtime_DebugReferencedBy(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010321 ASSERT(args.length() == 3);
10322
10323 // First perform a full GC in order to avoid references from dead objects.
ager@chromium.orgab99eea2009-08-25 07:05:41 +000010324 Heap::CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010325
10326 // Check parameters.
10327 CONVERT_CHECKED(JSObject, target, args[0]);
10328 Object* instance_filter = args[1];
10329 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
10330 instance_filter->IsJSObject());
10331 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
10332 RUNTIME_ASSERT(max_references >= 0);
10333
10334 // Get the constructor function for context extension and arguments array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010335 JSObject* arguments_boilerplate =
10336 Top::context()->global_context()->arguments_boilerplate();
10337 JSFunction* arguments_function =
10338 JSFunction::cast(arguments_boilerplate->map()->constructor());
10339
10340 // Get the number of referencing objects.
10341 int count;
10342 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000010343 NULL, 0, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010344
10345 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010346 Object* object;
10347 { MaybeObject* maybe_object = Heap::AllocateFixedArray(count);
10348 if (!maybe_object->ToObject(&object)) return maybe_object;
10349 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010350 FixedArray* instances = FixedArray::cast(object);
10351
10352 // Fill the referencing objects.
10353 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000010354 instances, count, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010355
10356 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010357 Object* result;
10358 { MaybeObject* maybe_result = Heap::AllocateJSObject(
10359 Top::context()->global_context()->array_function());
10360 if (!maybe_result->ToObject(&result)) return maybe_result;
10361 }
10362 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010363 return result;
10364}
10365
10366
10367// Helper function used by Runtime_DebugConstructedBy below.
10368static int DebugConstructedBy(JSFunction* constructor, int max_references,
10369 FixedArray* instances, int instances_size) {
10370 AssertNoAllocation no_alloc;
10371
10372 // Iterate the heap.
10373 int count = 0;
10374 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010375 HeapObject* heap_obj = NULL;
10376 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010377 (max_references == 0 || count < max_references)) {
10378 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010379 if (heap_obj->IsJSObject()) {
10380 JSObject* obj = JSObject::cast(heap_obj);
10381 if (obj->map()->constructor() == constructor) {
10382 // Valid reference found add to instance array if supplied an update
10383 // count.
10384 if (instances != NULL && count < instances_size) {
10385 instances->set(count, obj);
10386 }
10387 count++;
10388 }
10389 }
10390 }
10391
10392 // Return the number of referencing objects found.
10393 return count;
10394}
10395
10396
10397// Scan the heap for objects constructed by a specific function.
10398// args[0]: the constructor to find instances of
10399// args[1]: the the maximum number of objects to return
lrn@chromium.org303ada72010-10-27 09:33:13 +000010400static MaybeObject* Runtime_DebugConstructedBy(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010401 ASSERT(args.length() == 2);
10402
10403 // First perform a full GC in order to avoid dead objects.
ager@chromium.orgab99eea2009-08-25 07:05:41 +000010404 Heap::CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010405
10406 // Check parameters.
10407 CONVERT_CHECKED(JSFunction, constructor, args[0]);
10408 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
10409 RUNTIME_ASSERT(max_references >= 0);
10410
10411 // Get the number of referencing objects.
10412 int count;
10413 count = DebugConstructedBy(constructor, max_references, NULL, 0);
10414
10415 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010416 Object* object;
10417 { MaybeObject* maybe_object = Heap::AllocateFixedArray(count);
10418 if (!maybe_object->ToObject(&object)) return maybe_object;
10419 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010420 FixedArray* instances = FixedArray::cast(object);
10421
10422 // Fill the referencing objects.
10423 count = DebugConstructedBy(constructor, max_references, instances, count);
10424
10425 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010426 Object* result;
10427 { MaybeObject* maybe_result = Heap::AllocateJSObject(
10428 Top::context()->global_context()->array_function());
10429 if (!maybe_result->ToObject(&result)) return maybe_result;
10430 }
10431 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010432 return result;
10433}
10434
10435
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010436// Find the effective prototype object as returned by __proto__.
10437// args[0]: the object to find the prototype for.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010438static MaybeObject* Runtime_DebugGetPrototype(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010439 ASSERT(args.length() == 1);
10440
10441 CONVERT_CHECKED(JSObject, obj, args[0]);
10442
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010443 // Use the __proto__ accessor.
10444 return Accessors::ObjectPrototype.getter(obj, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010445}
10446
10447
lrn@chromium.org303ada72010-10-27 09:33:13 +000010448static MaybeObject* Runtime_SystemBreak(Arguments args) {
mads.s.ager31e71382008-08-13 09:32:07 +000010449 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010450 CPU::DebugBreak();
10451 return Heap::undefined_value();
10452}
10453
10454
lrn@chromium.org303ada72010-10-27 09:33:13 +000010455static MaybeObject* Runtime_DebugDisassembleFunction(Arguments args) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010456#ifdef DEBUG
10457 HandleScope scope;
10458 ASSERT(args.length() == 1);
10459 // Get the function and make sure it is compiled.
10460 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010461 Handle<SharedFunctionInfo> shared(func->shared());
10462 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010463 return Failure::Exception();
10464 }
10465 func->code()->PrintLn();
10466#endif // DEBUG
10467 return Heap::undefined_value();
10468}
ager@chromium.org9085a012009-05-11 19:22:57 +000010469
10470
lrn@chromium.org303ada72010-10-27 09:33:13 +000010471static MaybeObject* Runtime_DebugDisassembleConstructor(Arguments args) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000010472#ifdef DEBUG
10473 HandleScope scope;
10474 ASSERT(args.length() == 1);
10475 // Get the function and make sure it is compiled.
10476 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010477 Handle<SharedFunctionInfo> shared(func->shared());
10478 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000010479 return Failure::Exception();
10480 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010481 shared->construct_stub()->PrintLn();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000010482#endif // DEBUG
10483 return Heap::undefined_value();
10484}
10485
10486
lrn@chromium.org303ada72010-10-27 09:33:13 +000010487static MaybeObject* Runtime_FunctionGetInferredName(Arguments args) {
ager@chromium.org9085a012009-05-11 19:22:57 +000010488 NoHandleAllocation ha;
10489 ASSERT(args.length() == 1);
10490
10491 CONVERT_CHECKED(JSFunction, f, args[0]);
10492 return f->shared()->inferred_name();
10493}
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010494
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010495
10496static int FindSharedFunctionInfosForScript(Script* script,
10497 FixedArray* buffer) {
10498 AssertNoAllocation no_allocations;
10499
10500 int counter = 0;
10501 int buffer_size = buffer->length();
10502 HeapIterator iterator;
10503 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
10504 ASSERT(obj != NULL);
10505 if (!obj->IsSharedFunctionInfo()) {
10506 continue;
10507 }
10508 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
10509 if (shared->script() != script) {
10510 continue;
10511 }
10512 if (counter < buffer_size) {
10513 buffer->set(counter, shared);
10514 }
10515 counter++;
10516 }
10517 return counter;
10518}
10519
10520// For a script finds all SharedFunctionInfo's in the heap that points
10521// to this script. Returns JSArray of SharedFunctionInfo wrapped
10522// in OpaqueReferences.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010523static MaybeObject* Runtime_LiveEditFindSharedFunctionInfosForScript(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010524 Arguments args) {
10525 ASSERT(args.length() == 1);
10526 HandleScope scope;
10527 CONVERT_CHECKED(JSValue, script_value, args[0]);
10528
10529 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
10530
10531 const int kBufferSize = 32;
10532
10533 Handle<FixedArray> array;
10534 array = Factory::NewFixedArray(kBufferSize);
10535 int number = FindSharedFunctionInfosForScript(*script, *array);
10536 if (number > kBufferSize) {
10537 array = Factory::NewFixedArray(number);
10538 FindSharedFunctionInfosForScript(*script, *array);
10539 }
10540
10541 Handle<JSArray> result = Factory::NewJSArrayWithElements(array);
10542 result->set_length(Smi::FromInt(number));
10543
10544 LiveEdit::WrapSharedFunctionInfos(result);
10545
10546 return *result;
10547}
10548
10549// For a script calculates compilation information about all its functions.
10550// The script source is explicitly specified by the second argument.
10551// The source of the actual script is not used, however it is important that
10552// all generated code keeps references to this particular instance of script.
10553// Returns a JSArray of compilation infos. The array is ordered so that
10554// each function with all its descendant is always stored in a continues range
10555// with the function itself going first. The root function is a script function.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010556static MaybeObject* Runtime_LiveEditGatherCompileInfo(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010557 ASSERT(args.length() == 2);
10558 HandleScope scope;
10559 CONVERT_CHECKED(JSValue, script, args[0]);
10560 CONVERT_ARG_CHECKED(String, source, 1);
10561 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
10562
10563 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
10564
10565 if (Top::has_pending_exception()) {
10566 return Failure::Exception();
10567 }
10568
10569 return result;
10570}
10571
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010572// Changes the source of the script to a new_source.
10573// If old_script_name is provided (i.e. is a String), also creates a copy of
10574// the script with its original source and sends notification to debugger.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010575static MaybeObject* Runtime_LiveEditReplaceScript(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010576 ASSERT(args.length() == 3);
10577 HandleScope scope;
10578 CONVERT_CHECKED(JSValue, original_script_value, args[0]);
10579 CONVERT_ARG_CHECKED(String, new_source, 1);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010580 Handle<Object> old_script_name(args[2]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010581
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010582 CONVERT_CHECKED(Script, original_script_pointer,
10583 original_script_value->value());
10584 Handle<Script> original_script(original_script_pointer);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010585
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010586 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
10587 new_source,
10588 old_script_name);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010589
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010590 if (old_script->IsScript()) {
10591 Handle<Script> script_handle(Script::cast(old_script));
10592 return *(GetScriptWrapper(script_handle));
10593 } else {
10594 return Heap::null_value();
10595 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010596}
10597
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010598
10599static MaybeObject* Runtime_LiveEditFunctionSourceUpdated(Arguments args) {
10600 ASSERT(args.length() == 1);
10601 HandleScope scope;
10602 CONVERT_ARG_CHECKED(JSArray, shared_info, 0);
10603 return LiveEdit::FunctionSourceUpdated(shared_info);
10604}
10605
10606
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010607// Replaces code of SharedFunctionInfo with a new one.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010608static MaybeObject* Runtime_LiveEditReplaceFunctionCode(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010609 ASSERT(args.length() == 2);
10610 HandleScope scope;
10611 CONVERT_ARG_CHECKED(JSArray, new_compile_info, 0);
10612 CONVERT_ARG_CHECKED(JSArray, shared_info, 1);
10613
ager@chromium.orgac091b72010-05-05 07:34:42 +000010614 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010615}
10616
10617// Connects SharedFunctionInfo to another script.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010618static MaybeObject* Runtime_LiveEditFunctionSetScript(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010619 ASSERT(args.length() == 2);
10620 HandleScope scope;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010621 Handle<Object> function_object(args[0]);
10622 Handle<Object> script_object(args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010623
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010624 if (function_object->IsJSValue()) {
10625 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
10626 if (script_object->IsJSValue()) {
10627 CONVERT_CHECKED(Script, script, JSValue::cast(*script_object)->value());
10628 script_object = Handle<Object>(script);
10629 }
10630
10631 LiveEdit::SetFunctionScript(function_wrapper, script_object);
10632 } else {
10633 // Just ignore this. We may not have a SharedFunctionInfo for some functions
10634 // and we check it in this function.
10635 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010636
10637 return Heap::undefined_value();
10638}
10639
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010640
10641// In a code of a parent function replaces original function as embedded object
10642// with a substitution one.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010643static MaybeObject* Runtime_LiveEditReplaceRefToNestedFunction(Arguments args) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010644 ASSERT(args.length() == 3);
10645 HandleScope scope;
10646
10647 CONVERT_ARG_CHECKED(JSValue, parent_wrapper, 0);
10648 CONVERT_ARG_CHECKED(JSValue, orig_wrapper, 1);
10649 CONVERT_ARG_CHECKED(JSValue, subst_wrapper, 2);
10650
10651 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
10652 subst_wrapper);
10653
10654 return Heap::undefined_value();
10655}
10656
10657
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010658// Updates positions of a shared function info (first parameter) according
10659// to script source change. Text change is described in second parameter as
10660// array of groups of 3 numbers:
10661// (change_begin, change_end, change_end_new_position).
10662// Each group describes a change in text; groups are sorted by change_begin.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010663static MaybeObject* Runtime_LiveEditPatchFunctionPositions(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010664 ASSERT(args.length() == 2);
10665 HandleScope scope;
10666 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
10667 CONVERT_ARG_CHECKED(JSArray, position_change_array, 1);
10668
ager@chromium.orgac091b72010-05-05 07:34:42 +000010669 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010670}
10671
10672
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010673// For array of SharedFunctionInfo's (each wrapped in JSValue)
10674// checks that none of them have activations on stacks (of any thread).
10675// Returns array of the same length with corresponding results of
10676// LiveEdit::FunctionPatchabilityStatus type.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010677static MaybeObject* Runtime_LiveEditCheckAndDropActivations(Arguments args) {
ager@chromium.org357bf652010-04-12 11:30:10 +000010678 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010679 HandleScope scope;
10680 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
ager@chromium.org357bf652010-04-12 11:30:10 +000010681 CONVERT_BOOLEAN_CHECKED(do_drop, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010682
ager@chromium.org357bf652010-04-12 11:30:10 +000010683 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010684}
10685
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000010686// Compares 2 strings line-by-line, then token-wise and returns diff in form
10687// of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
10688// of diff chunks.
10689static MaybeObject* Runtime_LiveEditCompareStrings(Arguments args) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010690 ASSERT(args.length() == 2);
10691 HandleScope scope;
10692 CONVERT_ARG_CHECKED(String, s1, 0);
10693 CONVERT_ARG_CHECKED(String, s2, 1);
10694
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000010695 return *LiveEdit::CompareStrings(s1, s2);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010696}
10697
10698
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010699
fschneider@chromium.org086aac62010-03-17 13:18:24 +000010700// A testing entry. Returns statement position which is the closest to
10701// source_position.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010702static MaybeObject* Runtime_GetFunctionCodePositionFromSource(Arguments args) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +000010703 ASSERT(args.length() == 2);
10704 HandleScope scope;
10705 CONVERT_ARG_CHECKED(JSFunction, function, 0);
10706 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
10707
10708 Handle<Code> code(function->code());
10709
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010710 if (code->kind() != Code::FUNCTION &&
10711 code->kind() != Code::OPTIMIZED_FUNCTION) {
10712 return Heap::undefined_value();
10713 }
10714
10715 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
fschneider@chromium.org086aac62010-03-17 13:18:24 +000010716 int closest_pc = 0;
10717 int distance = kMaxInt;
10718 while (!it.done()) {
10719 int statement_position = static_cast<int>(it.rinfo()->data());
10720 // Check if this break point is closer that what was previously found.
10721 if (source_position <= statement_position &&
10722 statement_position - source_position < distance) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +000010723 closest_pc =
10724 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
fschneider@chromium.org086aac62010-03-17 13:18:24 +000010725 distance = statement_position - source_position;
10726 // Check whether we can't get any closer.
10727 if (distance == 0) break;
10728 }
10729 it.next();
10730 }
10731
10732 return Smi::FromInt(closest_pc);
10733}
10734
10735
ager@chromium.org357bf652010-04-12 11:30:10 +000010736// Calls specified function with or without entering the debugger.
10737// This is used in unit tests to run code as if debugger is entered or simply
10738// to have a stack with C++ frame in the middle.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010739static MaybeObject* Runtime_ExecuteInDebugContext(Arguments args) {
ager@chromium.org357bf652010-04-12 11:30:10 +000010740 ASSERT(args.length() == 2);
10741 HandleScope scope;
10742 CONVERT_ARG_CHECKED(JSFunction, function, 0);
10743 CONVERT_BOOLEAN_CHECKED(without_debugger, args[1]);
10744
10745 Handle<Object> result;
10746 bool pending_exception;
10747 {
10748 if (without_debugger) {
10749 result = Execution::Call(function, Top::global(), 0, NULL,
10750 &pending_exception);
10751 } else {
10752 EnterDebugger enter_debugger;
10753 result = Execution::Call(function, Top::global(), 0, NULL,
10754 &pending_exception);
10755 }
10756 }
10757 if (!pending_exception) {
10758 return *result;
10759 } else {
10760 return Failure::Exception();
10761 }
10762}
10763
10764
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000010765// Sets a v8 flag.
10766static MaybeObject* Runtime_SetFlags(Arguments args) {
10767 CONVERT_CHECKED(String, arg, args[0]);
10768 SmartPointer<char> flags =
10769 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
10770 FlagList::SetFlagsFromString(*flags, StrLength(*flags));
10771 return Heap::undefined_value();
10772}
10773
10774
10775// Performs a GC.
10776// Presently, it only does a full GC.
10777static MaybeObject* Runtime_CollectGarbage(Arguments args) {
10778 Heap::CollectAllGarbage(true);
10779 return Heap::undefined_value();
10780}
10781
10782
10783// Gets the current heap usage.
10784static MaybeObject* Runtime_GetHeapUsage(Arguments args) {
10785 int usage = static_cast<int>(Heap::SizeOfObjects());
10786 if (!Smi::IsValid(usage)) {
10787 return *Factory::NewNumberFromInt(usage);
10788 }
10789 return Smi::FromInt(usage);
10790}
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010791#endif // ENABLE_DEBUGGER_SUPPORT
10792
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010793
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000010794#ifdef ENABLE_LOGGING_AND_PROFILING
lrn@chromium.org303ada72010-10-27 09:33:13 +000010795static MaybeObject* Runtime_ProfilerResume(Arguments args) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010796 NoHandleAllocation ha;
ager@chromium.org5c838252010-02-19 08:53:10 +000010797 ASSERT(args.length() == 2);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010798
10799 CONVERT_CHECKED(Smi, smi_modules, args[0]);
ager@chromium.org5c838252010-02-19 08:53:10 +000010800 CONVERT_CHECKED(Smi, smi_tag, args[1]);
10801 v8::V8::ResumeProfilerEx(smi_modules->value(), smi_tag->value());
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010802 return Heap::undefined_value();
10803}
10804
10805
lrn@chromium.org303ada72010-10-27 09:33:13 +000010806static MaybeObject* Runtime_ProfilerPause(Arguments args) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010807 NoHandleAllocation ha;
ager@chromium.org5c838252010-02-19 08:53:10 +000010808 ASSERT(args.length() == 2);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010809
10810 CONVERT_CHECKED(Smi, smi_modules, args[0]);
ager@chromium.org5c838252010-02-19 08:53:10 +000010811 CONVERT_CHECKED(Smi, smi_tag, args[1]);
10812 v8::V8::PauseProfilerEx(smi_modules->value(), smi_tag->value());
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010813 return Heap::undefined_value();
10814}
10815
10816#endif // ENABLE_LOGGING_AND_PROFILING
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010817
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010818// Finds the script object from the script data. NOTE: This operation uses
10819// heap traversal to find the function generated for the source position
10820// for the requested break point. For lazily compiled functions several heap
10821// traversals might be required rendering this operation as a rather slow
10822// operation. However for setting break points which is normally done through
10823// some kind of user interaction the performance is not crucial.
10824static Handle<Object> Runtime_GetScriptFromScriptName(
10825 Handle<String> script_name) {
10826 // Scan the heap for Script objects to find the script with the requested
10827 // script data.
10828 Handle<Script> script;
10829 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010830 HeapObject* obj = NULL;
10831 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010832 // If a script is found check if it has the script data requested.
10833 if (obj->IsScript()) {
10834 if (Script::cast(obj)->name()->IsString()) {
10835 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
10836 script = Handle<Script>(Script::cast(obj));
10837 }
10838 }
10839 }
10840 }
10841
10842 // If no script with the requested script data is found return undefined.
10843 if (script.is_null()) return Factory::undefined_value();
10844
10845 // Return the script found.
10846 return GetScriptWrapper(script);
10847}
10848
10849
10850// Get the script object from script data. NOTE: Regarding performance
10851// see the NOTE for GetScriptFromScriptData.
10852// args[0]: script data for the script to find the source for
lrn@chromium.org303ada72010-10-27 09:33:13 +000010853static MaybeObject* Runtime_GetScript(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010854 HandleScope scope;
10855
10856 ASSERT(args.length() == 1);
10857
10858 CONVERT_CHECKED(String, script_name, args[0]);
10859
10860 // Find the requested script.
10861 Handle<Object> result =
10862 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
10863 return *result;
10864}
10865
10866
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010867// Determines whether the given stack frame should be displayed in
10868// a stack trace. The caller is the error constructor that asked
10869// for the stack trace to be collected. The first time a construct
10870// call to this function is encountered it is skipped. The seen_caller
10871// in/out parameter is used to remember if the caller has been seen
10872// yet.
10873static bool ShowFrameInStackTrace(StackFrame* raw_frame, Object* caller,
10874 bool* seen_caller) {
10875 // Only display JS frames.
10876 if (!raw_frame->is_java_script())
10877 return false;
10878 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
10879 Object* raw_fun = frame->function();
10880 // Not sure when this can happen but skip it just in case.
10881 if (!raw_fun->IsJSFunction())
10882 return false;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010883 if ((raw_fun == caller) && !(*seen_caller)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010884 *seen_caller = true;
10885 return false;
10886 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010887 // Skip all frames until we've seen the caller. Also, skip the most
10888 // obvious builtin calls. Some builtin calls (such as Number.ADD
10889 // which is invoked using 'call') are very difficult to recognize
10890 // so we're leaving them in for now.
10891 return *seen_caller && !frame->receiver()->IsJSBuiltinsObject();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010892}
10893
10894
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010895// Collect the raw data for a stack trace. Returns an array of 4
10896// element segments each containing a receiver, function, code and
10897// native code offset.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010898static MaybeObject* Runtime_CollectStackTrace(Arguments args) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010899 ASSERT_EQ(args.length(), 2);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010900 Handle<Object> caller = args.at<Object>(0);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010901 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[1]);
10902
10903 HandleScope scope;
10904
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000010905 limit = Max(limit, 0); // Ensure that limit is not negative.
10906 int initial_size = Min(limit, 10);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010907 Handle<JSArray> result = Factory::NewJSArray(initial_size * 4);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010908
10909 StackFrameIterator iter;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010910 // If the caller parameter is a function we skip frames until we're
10911 // under it before starting to collect.
10912 bool seen_caller = !caller->IsJSFunction();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010913 int cursor = 0;
10914 int frames_seen = 0;
10915 while (!iter.done() && frames_seen < limit) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010916 StackFrame* raw_frame = iter.frame();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010917 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010918 frames_seen++;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010919 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010920 List<FrameSummary> frames(3); // Max 2 levels of inlining.
10921 frame->Summarize(&frames);
10922 for (int i = frames.length() - 1; i >= 0; i--) {
10923 Handle<Object> recv = frames[i].receiver();
10924 Handle<JSFunction> fun = frames[i].function();
10925 Handle<Code> code = frames[i].code();
10926 Handle<Smi> offset(Smi::FromInt(frames[i].offset()));
10927 FixedArray* elements = FixedArray::cast(result->elements());
10928 if (cursor + 3 < elements->length()) {
10929 elements->set(cursor++, *recv);
10930 elements->set(cursor++, *fun);
10931 elements->set(cursor++, *code);
10932 elements->set(cursor++, *offset);
10933 } else {
10934 SetElement(result, cursor++, recv);
10935 SetElement(result, cursor++, fun);
10936 SetElement(result, cursor++, code);
10937 SetElement(result, cursor++, offset);
10938 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010939 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010940 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010941 iter.Advance();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010942 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010943
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010944 result->set_length(Smi::FromInt(cursor));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010945 return *result;
10946}
10947
10948
ager@chromium.org3811b432009-10-28 14:53:37 +000010949// Returns V8 version as a string.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010950static MaybeObject* Runtime_GetV8Version(Arguments args) {
ager@chromium.org3811b432009-10-28 14:53:37 +000010951 ASSERT_EQ(args.length(), 0);
10952
10953 NoHandleAllocation ha;
10954
10955 const char* version_string = v8::V8::GetVersion();
10956
10957 return Heap::AllocateStringFromAscii(CStrVector(version_string), NOT_TENURED);
10958}
10959
10960
lrn@chromium.org303ada72010-10-27 09:33:13 +000010961static MaybeObject* Runtime_Abort(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010962 ASSERT(args.length() == 2);
10963 OS::PrintError("abort: %s\n", reinterpret_cast<char*>(args[0]) +
10964 Smi::cast(args[1])->value());
10965 Top::PrintStack();
10966 OS::Abort();
10967 UNREACHABLE();
10968 return NULL;
10969}
10970
10971
lrn@chromium.org303ada72010-10-27 09:33:13 +000010972static MaybeObject* Runtime_GetFromCache(Arguments args) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010973 // This is only called from codegen, so checks might be more lax.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000010974 CONVERT_CHECKED(JSFunctionResultCache, cache, args[0]);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010975 Object* key = args[1];
10976
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000010977 int finger_index = cache->finger_index();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010978 Object* o = cache->get(finger_index);
10979 if (o == key) {
10980 // The fastest case: hit the same place again.
10981 return cache->get(finger_index + 1);
10982 }
10983
10984 for (int i = finger_index - 2;
10985 i >= JSFunctionResultCache::kEntriesIndex;
10986 i -= 2) {
10987 o = cache->get(i);
10988 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000010989 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010990 return cache->get(i + 1);
10991 }
10992 }
10993
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000010994 int size = cache->size();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010995 ASSERT(size <= cache->length());
10996
10997 for (int i = size - 2; i > finger_index; i -= 2) {
10998 o = cache->get(i);
10999 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011000 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011001 return cache->get(i + 1);
11002 }
11003 }
11004
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011005 // There is no value in the cache. Invoke the function and cache result.
11006 HandleScope scope;
11007
11008 Handle<JSFunctionResultCache> cache_handle(cache);
11009 Handle<Object> key_handle(key);
11010 Handle<Object> value;
11011 {
11012 Handle<JSFunction> factory(JSFunction::cast(
11013 cache_handle->get(JSFunctionResultCache::kFactoryIndex)));
11014 // TODO(antonm): consider passing a receiver when constructing a cache.
11015 Handle<Object> receiver(Top::global_context()->global());
11016 // This handle is nor shared, nor used later, so it's safe.
11017 Object** argv[] = { key_handle.location() };
11018 bool pending_exception = false;
11019 value = Execution::Call(factory,
11020 receiver,
11021 1,
11022 argv,
11023 &pending_exception);
11024 if (pending_exception) return Failure::Exception();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011025 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011026
11027#ifdef DEBUG
11028 cache_handle->JSFunctionResultCacheVerify();
11029#endif
11030
11031 // Function invocation may have cleared the cache. Reread all the data.
11032 finger_index = cache_handle->finger_index();
11033 size = cache_handle->size();
11034
11035 // If we have spare room, put new data into it, otherwise evict post finger
11036 // entry which is likely to be the least recently used.
11037 int index = -1;
11038 if (size < cache_handle->length()) {
11039 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize);
11040 index = size;
11041 } else {
11042 index = finger_index + JSFunctionResultCache::kEntrySize;
11043 if (index == cache_handle->length()) {
11044 index = JSFunctionResultCache::kEntriesIndex;
11045 }
11046 }
11047
11048 ASSERT(index % 2 == 0);
11049 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
11050 ASSERT(index < cache_handle->length());
11051
11052 cache_handle->set(index, *key_handle);
11053 cache_handle->set(index + 1, *value);
11054 cache_handle->set_finger_index(index);
11055
11056#ifdef DEBUG
11057 cache_handle->JSFunctionResultCacheVerify();
11058#endif
11059
11060 return *value;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011061}
11062
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000011063
11064static MaybeObject* Runtime_NewMessageObject(Arguments args) {
11065 HandleScope scope;
11066 CONVERT_ARG_CHECKED(String, type, 0);
11067 CONVERT_ARG_CHECKED(JSArray, arguments, 1);
11068 return *Factory::NewJSMessageObject(type,
11069 arguments,
11070 0,
11071 0,
11072 Factory::undefined_value(),
11073 Factory::undefined_value(),
11074 Factory::undefined_value());
11075}
11076
11077
11078static MaybeObject* Runtime_MessageGetType(Arguments args) {
11079 CONVERT_CHECKED(JSMessageObject, message, args[0]);
11080 return message->type();
11081}
11082
11083
11084static MaybeObject* Runtime_MessageGetArguments(Arguments args) {
11085 CONVERT_CHECKED(JSMessageObject, message, args[0]);
11086 return message->arguments();
11087}
11088
11089
11090static MaybeObject* Runtime_MessageGetStartPosition(Arguments args) {
11091 CONVERT_CHECKED(JSMessageObject, message, args[0]);
11092 return Smi::FromInt(message->start_position());
11093}
11094
11095
11096static MaybeObject* Runtime_MessageGetScript(Arguments args) {
11097 CONVERT_CHECKED(JSMessageObject, message, args[0]);
11098 return message->script();
11099}
11100
11101
kasper.lund44510672008-07-25 07:37:58 +000011102#ifdef DEBUG
11103// ListNatives is ONLY used by the fuzz-natives.js in debug mode
11104// Exclude the code in release mode.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011105static MaybeObject* Runtime_ListNatives(Arguments args) {
mads.s.ager31e71382008-08-13 09:32:07 +000011106 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011107 HandleScope scope;
11108 Handle<JSArray> result = Factory::NewJSArray(0);
11109 int index = 0;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000011110 bool inline_runtime_functions = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +000011111#define ADD_ENTRY(Name, argc, ressize) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011112 { \
11113 HandleScope inner; \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000011114 Handle<String> name; \
11115 /* Inline runtime functions have an underscore in front of the name. */ \
11116 if (inline_runtime_functions) { \
11117 name = Factory::NewStringFromAscii( \
11118 Vector<const char>("_" #Name, StrLength("_" #Name))); \
11119 } else { \
11120 name = Factory::NewStringFromAscii( \
11121 Vector<const char>(#Name, StrLength(#Name))); \
11122 } \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011123 Handle<JSArray> pair = Factory::NewJSArray(0); \
11124 SetElement(pair, 0, name); \
11125 SetElement(pair, 1, Handle<Smi>(Smi::FromInt(argc))); \
11126 SetElement(result, index++, pair); \
11127 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000011128 inline_runtime_functions = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011129 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000011130 inline_runtime_functions = true;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011131 INLINE_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000011132 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011133#undef ADD_ENTRY
11134 return *result;
11135}
kasper.lund44510672008-07-25 07:37:58 +000011136#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011137
11138
lrn@chromium.org303ada72010-10-27 09:33:13 +000011139static MaybeObject* Runtime_Log(Arguments args) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000011140 ASSERT(args.length() == 2);
ager@chromium.org381abbb2009-02-25 13:23:22 +000011141 CONVERT_CHECKED(String, format, args[0]);
11142 CONVERT_CHECKED(JSArray, elms, args[1]);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000011143 Vector<const char> chars = format->ToAsciiVector();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000011144 Logger::LogRuntime(chars, elms);
11145 return Heap::undefined_value();
11146}
11147
11148
lrn@chromium.org303ada72010-10-27 09:33:13 +000011149static MaybeObject* Runtime_IS_VAR(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011150 UNREACHABLE(); // implemented as macro in the parser
11151 return NULL;
11152}
11153
11154
11155// ----------------------------------------------------------------------------
11156// Implementation of Runtime
11157
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011158#define F(name, number_of_args, result_size) \
11159 { Runtime::k##name, Runtime::RUNTIME, #name, \
11160 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011161
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011162
11163#define I(name, number_of_args, result_size) \
11164 { Runtime::kInline##name, Runtime::INLINE, \
11165 "_" #name, NULL, number_of_args, result_size },
11166
11167Runtime::Function kIntrinsicFunctions[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011168 RUNTIME_FUNCTION_LIST(F)
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011169 INLINE_FUNCTION_LIST(I)
11170 INLINE_RUNTIME_FUNCTION_LIST(I)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011171};
11172
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011173
lrn@chromium.org303ada72010-10-27 09:33:13 +000011174MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Object* dictionary) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011175 ASSERT(dictionary != NULL);
11176 ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
11177 for (int i = 0; i < kNumFunctions; ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000011178 Object* name_symbol;
11179 { MaybeObject* maybe_name_symbol =
11180 Heap::LookupAsciiSymbol(kIntrinsicFunctions[i].name);
11181 if (!maybe_name_symbol->ToObject(&name_symbol)) return maybe_name_symbol;
11182 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011183 StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011184 { MaybeObject* maybe_dictionary = string_dictionary->Add(
11185 String::cast(name_symbol),
11186 Smi::FromInt(i),
11187 PropertyDetails(NONE, NORMAL));
11188 if (!maybe_dictionary->ToObject(&dictionary)) {
11189 // Non-recoverable failure. Calling code must restart heap
11190 // initialization.
11191 return maybe_dictionary;
11192 }
11193 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011194 }
11195 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011196}
11197
11198
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011199Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
11200 int entry = Heap::intrinsic_function_names()->FindEntry(*name);
11201 if (entry != kNotFound) {
11202 Object* smi_index = Heap::intrinsic_function_names()->ValueAt(entry);
11203 int function_index = Smi::cast(smi_index)->value();
11204 return &(kIntrinsicFunctions[function_index]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011205 }
11206 return NULL;
11207}
11208
11209
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011210Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
11211 return &(kIntrinsicFunctions[static_cast<int>(id)]);
11212}
11213
11214
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011215void Runtime::PerformGC(Object* result) {
11216 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000011217 if (failure->IsRetryAfterGC()) {
11218 // Try to do a garbage collection; ignore it if it fails. The C
11219 // entry stub will throw an out-of-memory exception in that case.
whesse@chromium.org4a5224e2010-10-20 12:37:07 +000011220 Heap::CollectGarbage(failure->allocation_space());
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000011221 } else {
11222 // Handle last resort GC and make sure to allow future allocations
11223 // to grow the heap without causing GCs (if possible).
11224 Counters::gc_last_resort_from_js.Increment();
ager@chromium.orgab99eea2009-08-25 07:05:41 +000011225 Heap::CollectAllGarbage(false);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000011226 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011227}
11228
11229
11230} } // namespace v8::internal