blob: 92fa840316a0a372159db9614690844437d38968 [file] [log] [blame]
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00001// Copyright 2011 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"
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000043#include "global-handles.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000044#include "jsregexp.h"
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000045#include "liveedit.h"
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000046#include "liveobjectlist-inl.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000047#include "parser.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000048#include "platform.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000049#include "runtime-profiler.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000050#include "runtime.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000051#include "scopeinfo.h"
ager@chromium.org7c537e22008-10-16 08:43:32 +000052#include "smart-pointer.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000053#include "string-search.h"
ager@chromium.org18ad94b2009-09-02 08:22:29 +000054#include "stub-cache.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000055#include "v8threads.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000056#include "vm-state-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000057
kasperl@chromium.org71affb52009-05-26 05:44:31 +000058namespace v8 {
59namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000060
61
ager@chromium.org3e875802009-06-29 08:26:34 +000062#define RUNTIME_ASSERT(value) \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000063 if (!(value)) return isolate->ThrowIllegalOperation();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000064
65// Cast the given object to a value of the specified type and store
66// it in a variable with the given name. If the object is not of the
67// expected type call IllegalOperation and return.
68#define CONVERT_CHECKED(Type, name, obj) \
69 RUNTIME_ASSERT(obj->Is##Type()); \
70 Type* name = Type::cast(obj);
71
72#define CONVERT_ARG_CHECKED(Type, name, index) \
73 RUNTIME_ASSERT(args[index]->Is##Type()); \
74 Handle<Type> name = args.at<Type>(index);
75
kasper.lundbd3ec4e2008-07-09 11:06:54 +000076// Cast the given object to a boolean and store it in a variable with
77// the given name. If the object is not a boolean call IllegalOperation
78// and return.
79#define CONVERT_BOOLEAN_CHECKED(name, obj) \
80 RUNTIME_ASSERT(obj->IsBoolean()); \
81 bool name = (obj)->IsTrue();
82
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000083// Cast the given object to a Smi and store its value in an int variable
84// with the given name. If the object is not a Smi call IllegalOperation
85// and return.
86#define CONVERT_SMI_CHECKED(name, obj) \
87 RUNTIME_ASSERT(obj->IsSmi()); \
88 int name = Smi::cast(obj)->value();
89
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000090// Cast the given object to a double and store it in a variable with
91// the given name. If the object is not a number (as opposed to
92// the number not-a-number) call IllegalOperation and return.
93#define CONVERT_DOUBLE_CHECKED(name, obj) \
94 RUNTIME_ASSERT(obj->IsNumber()); \
95 double name = (obj)->Number();
96
97// Call the specified converter on the object *comand store the result in
98// a variable of the specified type with the given name. If the
99// object is not a Number call IllegalOperation and return.
100#define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \
101 RUNTIME_ASSERT(obj->IsNumber()); \
102 type name = NumberTo##Type(obj);
103
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000104
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000105MUST_USE_RESULT static MaybeObject* DeepCopyBoilerplate(Isolate* isolate,
106 JSObject* boilerplate) {
107 StackLimitCheck check(isolate);
108 if (check.HasOverflowed()) return isolate->StackOverflow();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000109
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000110 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000111 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000112 { MaybeObject* maybe_result = heap->CopyJSObject(boilerplate);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000113 if (!maybe_result->ToObject(&result)) return maybe_result;
114 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000115 JSObject* copy = JSObject::cast(result);
116
117 // Deep copy local properties.
118 if (copy->HasFastProperties()) {
119 FixedArray* properties = copy->properties();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000120 for (int i = 0; i < properties->length(); i++) {
121 Object* value = properties->get(i);
122 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000123 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000124 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000125 if (!maybe_result->ToObject(&result)) return maybe_result;
126 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000127 properties->set(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000128 }
129 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000130 int nof = copy->map()->inobject_properties();
131 for (int i = 0; i < nof; i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000132 Object* value = copy->InObjectPropertyAt(i);
133 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000134 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000135 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000136 if (!maybe_result->ToObject(&result)) return maybe_result;
137 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000138 copy->InObjectPropertyAtPut(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000139 }
140 }
141 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000142 { MaybeObject* maybe_result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000143 heap->AllocateFixedArray(copy->NumberOfLocalProperties(NONE));
lrn@chromium.org303ada72010-10-27 09:33:13 +0000144 if (!maybe_result->ToObject(&result)) return maybe_result;
145 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000146 FixedArray* names = FixedArray::cast(result);
147 copy->GetLocalPropertyNames(names, 0);
148 for (int i = 0; i < names->length(); i++) {
149 ASSERT(names->get(i)->IsString());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000150 String* key_string = String::cast(names->get(i));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000151 PropertyAttributes attributes =
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000152 copy->GetLocalPropertyAttribute(key_string);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000153 // Only deep copy fields from the object literal expression.
154 // In particular, don't try to copy the length attribute of
155 // an array.
156 if (attributes != NONE) continue;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000157 Object* value =
158 copy->GetProperty(key_string, &attributes)->ToObjectUnchecked();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000159 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000160 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000161 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000162 if (!maybe_result->ToObject(&result)) return maybe_result;
163 }
164 { MaybeObject* maybe_result =
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000165 // Creating object copy for literals. No strict mode needed.
166 copy->SetProperty(key_string, result, NONE, kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000167 if (!maybe_result->ToObject(&result)) return maybe_result;
168 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000169 }
170 }
171 }
172
173 // Deep copy local elements.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000174 // Pixel elements cannot be created using an object literal.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000175 ASSERT(!copy->HasExternalArrayElements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000176 switch (copy->GetElementsKind()) {
177 case JSObject::FAST_ELEMENTS: {
178 FixedArray* elements = FixedArray::cast(copy->elements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000179 if (elements->map() == heap->fixed_cow_array_map()) {
180 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000181#ifdef DEBUG
182 for (int i = 0; i < elements->length(); i++) {
183 ASSERT(!elements->get(i)->IsJSObject());
184 }
185#endif
186 } else {
187 for (int i = 0; i < elements->length(); i++) {
188 Object* value = elements->get(i);
189 if (value->IsJSObject()) {
190 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000191 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
192 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000193 if (!maybe_result->ToObject(&result)) return maybe_result;
194 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000195 elements->set(i, result);
196 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000197 }
198 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000199 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000200 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000201 case JSObject::DICTIONARY_ELEMENTS: {
202 NumberDictionary* element_dictionary = copy->element_dictionary();
203 int capacity = element_dictionary->Capacity();
204 for (int i = 0; i < capacity; i++) {
205 Object* k = element_dictionary->KeyAt(i);
206 if (element_dictionary->IsKey(k)) {
207 Object* value = element_dictionary->ValueAt(i);
208 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000209 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000210 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
211 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000212 if (!maybe_result->ToObject(&result)) return maybe_result;
213 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000214 element_dictionary->ValueAtPut(i, result);
215 }
216 }
217 }
218 break;
219 }
220 default:
221 UNREACHABLE();
222 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000223 }
224 return copy;
225}
226
227
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000228RUNTIME_FUNCTION(MaybeObject*, Runtime_CloneLiteralBoilerplate) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000229 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000230 return DeepCopyBoilerplate(isolate, boilerplate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000231}
232
233
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000234RUNTIME_FUNCTION(MaybeObject*, Runtime_CloneShallowLiteralBoilerplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000235 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000236 return isolate->heap()->CopyJSObject(boilerplate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000237}
238
239
ager@chromium.org236ad962008-09-25 09:45:57 +0000240static Handle<Map> ComputeObjectLiteralMap(
241 Handle<Context> context,
242 Handle<FixedArray> constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000243 bool* is_result_from_cache) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000244 Isolate* isolate = context->GetIsolate();
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000245 int properties_length = constant_properties->length();
246 int number_of_properties = properties_length / 2;
ager@chromium.org236ad962008-09-25 09:45:57 +0000247 if (FLAG_canonicalize_object_literal_maps) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000248 // Check that there are only symbols and array indices among keys.
ager@chromium.org236ad962008-09-25 09:45:57 +0000249 int number_of_symbol_keys = 0;
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000250 for (int p = 0; p != properties_length; p += 2) {
251 Object* key = constant_properties->get(p);
252 uint32_t element_index = 0;
253 if (key->IsSymbol()) {
254 number_of_symbol_keys++;
255 } else if (key->ToArrayIndex(&element_index)) {
256 // An index key does not require space in the property backing store.
257 number_of_properties--;
258 } else {
259 // Bail out as a non-symbol non-index key makes caching impossible.
260 // ASSERT to make sure that the if condition after the loop is false.
261 ASSERT(number_of_symbol_keys != number_of_properties);
262 break;
263 }
ager@chromium.org236ad962008-09-25 09:45:57 +0000264 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000265 // If we only have symbols and array indices among keys then we can
266 // use the map cache in the global context.
ager@chromium.org236ad962008-09-25 09:45:57 +0000267 const int kMaxKeys = 10;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000268 if ((number_of_symbol_keys == number_of_properties) &&
269 (number_of_symbol_keys < kMaxKeys)) {
ager@chromium.org236ad962008-09-25 09:45:57 +0000270 // Create the fixed array with the key.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000271 Handle<FixedArray> keys =
272 isolate->factory()->NewFixedArray(number_of_symbol_keys);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000273 if (number_of_symbol_keys > 0) {
274 int index = 0;
275 for (int p = 0; p < properties_length; p += 2) {
276 Object* key = constant_properties->get(p);
277 if (key->IsSymbol()) {
278 keys->set(index++, key);
279 }
280 }
281 ASSERT(index == number_of_symbol_keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000282 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000283 *is_result_from_cache = true;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000284 return isolate->factory()->ObjectLiteralMapFromCache(context, keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000285 }
286 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000287 *is_result_from_cache = false;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000288 return isolate->factory()->CopyMap(
ager@chromium.org32912102009-01-16 10:38:43 +0000289 Handle<Map>(context->object_function()->initial_map()),
290 number_of_properties);
ager@chromium.org236ad962008-09-25 09:45:57 +0000291}
292
293
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000294static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000295 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000296 Handle<FixedArray> literals,
297 Handle<FixedArray> constant_properties);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000298
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000299
300static Handle<Object> CreateObjectLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000301 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000302 Handle<FixedArray> literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000303 Handle<FixedArray> constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000304 bool should_have_fast_elements,
305 bool has_function_literal) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000306 // Get the global context from the literals array. This is the
307 // context in which the function was created and we use the object
308 // function from this context to create the object literal. We do
309 // not use the object function from the current global context
310 // because this might be the object function from another context
311 // which we should not have access to.
ager@chromium.org236ad962008-09-25 09:45:57 +0000312 Handle<Context> context =
313 Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals));
314
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000315 // In case we have function literals, we want the object to be in
316 // slow properties mode for now. We don't go in the map cache because
317 // maps with constant functions can't be shared if the functions are
318 // not the same (which is the common case).
319 bool is_result_from_cache = false;
320 Handle<Map> map = has_function_literal
321 ? Handle<Map>(context->object_function()->initial_map())
322 : ComputeObjectLiteralMap(context,
323 constant_properties,
324 &is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000325
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000326 Handle<JSObject> boilerplate = isolate->factory()->NewJSObjectFromMap(map);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000327
328 // Normalize the elements of the boilerplate to save space if needed.
329 if (!should_have_fast_elements) NormalizeElements(boilerplate);
330
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000331 // Add the constant properties to the boilerplate.
332 int length = constant_properties->length();
333 bool should_transform =
334 !is_result_from_cache && boilerplate->HasFastProperties();
335 if (should_transform || has_function_literal) {
336 // Normalize the properties of object to avoid n^2 behavior
337 // when extending the object multiple properties. Indicate the number of
338 // properties to be added.
339 NormalizeProperties(boilerplate, KEEP_INOBJECT_PROPERTIES, length / 2);
340 }
341
342 for (int index = 0; index < length; index +=2) {
343 Handle<Object> key(constant_properties->get(index+0), isolate);
344 Handle<Object> value(constant_properties->get(index+1), isolate);
345 if (value->IsFixedArray()) {
346 // The value contains the constant_properties of a
347 // simple object or array literal.
348 Handle<FixedArray> array = Handle<FixedArray>::cast(value);
349 value = CreateLiteralBoilerplate(isolate, literals, array);
350 if (value.is_null()) return value;
351 }
352 Handle<Object> result;
353 uint32_t element_index = 0;
354 if (key->IsSymbol()) {
355 if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) {
356 // Array index as string (uint32).
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000357 result = SetOwnElement(boilerplate,
358 element_index,
359 value,
360 kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000361 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000362 Handle<String> name(String::cast(*key));
363 ASSERT(!name->AsArrayIndex(&element_index));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000364 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
365 value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000366 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000367 } else if (key->ToArrayIndex(&element_index)) {
368 // Array index (uint32).
369 result = SetOwnElement(boilerplate,
370 element_index,
371 value,
372 kNonStrictMode);
373 } else {
374 // Non-uint32 number.
375 ASSERT(key->IsNumber());
376 double num = key->Number();
377 char arr[100];
378 Vector<char> buffer(arr, ARRAY_SIZE(arr));
379 const char* str = DoubleToCString(num, buffer);
380 Handle<String> name =
381 isolate->factory()->NewStringFromAscii(CStrVector(str));
382 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
383 value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000384 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000385 // If setting the property on the boilerplate throws an
386 // exception, the exception is converted to an empty handle in
387 // the handle based operations. In that case, we need to
388 // convert back to an exception.
389 if (result.is_null()) return result;
390 }
391
392 // Transform to fast properties if necessary. For object literals with
393 // containing function literals we defer this operation until after all
394 // computed properties have been assigned so that we can generate
395 // constant function properties.
396 if (should_transform && !has_function_literal) {
397 TransformToFastProperties(boilerplate,
398 boilerplate->map()->unused_property_fields());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000399 }
400
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000401 return boilerplate;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000402}
403
404
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000405static Handle<Object> CreateArrayLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000406 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000407 Handle<FixedArray> literals,
408 Handle<FixedArray> elements) {
409 // Create the JSArray.
410 Handle<JSFunction> constructor(
411 JSFunction::GlobalContextFromLiterals(*literals)->array_function());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000412 Handle<Object> object = isolate->factory()->NewJSObject(constructor);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000413
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000414 const bool is_cow =
415 (elements->map() == isolate->heap()->fixed_cow_array_map());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000416 Handle<FixedArray> copied_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000417 is_cow ? elements : isolate->factory()->CopyFixedArray(elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000418
419 Handle<FixedArray> content = Handle<FixedArray>::cast(copied_elements);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000420 if (is_cow) {
421#ifdef DEBUG
422 // Copy-on-write arrays must be shallow (and simple).
423 for (int i = 0; i < content->length(); i++) {
424 ASSERT(!content->get(i)->IsFixedArray());
425 }
426#endif
427 } else {
428 for (int i = 0; i < content->length(); i++) {
429 if (content->get(i)->IsFixedArray()) {
430 // The value contains the constant_properties of a
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000431 // simple object or array literal.
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000432 Handle<FixedArray> fa(FixedArray::cast(content->get(i)));
433 Handle<Object> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000434 CreateLiteralBoilerplate(isolate, literals, fa);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000435 if (result.is_null()) return result;
436 content->set(i, *result);
437 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000438 }
439 }
440
441 // Set the elements.
442 Handle<JSArray>::cast(object)->SetContent(*content);
443 return object;
444}
445
446
447static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000448 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000449 Handle<FixedArray> literals,
450 Handle<FixedArray> array) {
451 Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000452 const bool kHasNoFunctionLiteral = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000453 switch (CompileTimeValue::GetType(array)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000454 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000455 return CreateObjectLiteralBoilerplate(isolate,
456 literals,
457 elements,
458 true,
459 kHasNoFunctionLiteral);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000460 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000461 return CreateObjectLiteralBoilerplate(isolate,
462 literals,
463 elements,
464 false,
465 kHasNoFunctionLiteral);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000466 case CompileTimeValue::ARRAY_LITERAL:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000467 return CreateArrayLiteralBoilerplate(isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000468 default:
469 UNREACHABLE();
470 return Handle<Object>::null();
471 }
472}
473
474
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000475RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralBoilerplate) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000476 // Takes a FixedArray of elements containing the literal elements of
477 // the array literal and produces JSArray with those elements.
478 // Additionally takes the literals array of the surrounding function
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000479 // which contains the context from which to get the Array function
480 // to use for creating the array literal.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000481 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000482 ASSERT(args.length() == 3);
483 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
484 CONVERT_SMI_CHECKED(literals_index, args[1]);
485 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000486
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000487 Handle<Object> object =
488 CreateArrayLiteralBoilerplate(isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000489 if (object.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000490
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000491 // Update the functions literal and return the boilerplate.
492 literals->set(literals_index, *object);
493 return *object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000494}
495
496
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000497RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000498 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000499 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000500 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
501 CONVERT_SMI_CHECKED(literals_index, args[1]);
502 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000503 CONVERT_SMI_CHECKED(flags, args[3]);
504 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
505 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000506
507 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000508 Handle<Object> boilerplate(literals->get(literals_index), isolate);
509 if (*boilerplate == isolate->heap()->undefined_value()) {
510 boilerplate = CreateObjectLiteralBoilerplate(isolate,
511 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000512 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000513 should_have_fast_elements,
514 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000515 if (boilerplate.is_null()) return Failure::Exception();
516 // Update the functions literal and return the boilerplate.
517 literals->set(literals_index, *boilerplate);
518 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000519 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000520}
521
522
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000523RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000524 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000525 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000526 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
527 CONVERT_SMI_CHECKED(literals_index, args[1]);
528 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000529 CONVERT_SMI_CHECKED(flags, args[3]);
530 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
531 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000532
533 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000534 Handle<Object> boilerplate(literals->get(literals_index), isolate);
535 if (*boilerplate == isolate->heap()->undefined_value()) {
536 boilerplate = CreateObjectLiteralBoilerplate(isolate,
537 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000538 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000539 should_have_fast_elements,
540 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000541 if (boilerplate.is_null()) return Failure::Exception();
542 // Update the functions literal and return the boilerplate.
543 literals->set(literals_index, *boilerplate);
544 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000545 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000546}
547
548
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000549RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000550 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000551 ASSERT(args.length() == 3);
552 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
553 CONVERT_SMI_CHECKED(literals_index, args[1]);
554 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
555
556 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000557 Handle<Object> boilerplate(literals->get(literals_index), isolate);
558 if (*boilerplate == isolate->heap()->undefined_value()) {
559 boilerplate = CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000560 if (boilerplate.is_null()) return Failure::Exception();
561 // Update the functions literal and return the boilerplate.
562 literals->set(literals_index, *boilerplate);
563 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000564 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000565}
566
567
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000568RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000569 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000570 ASSERT(args.length() == 3);
571 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
572 CONVERT_SMI_CHECKED(literals_index, args[1]);
573 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
574
575 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000576 Handle<Object> boilerplate(literals->get(literals_index), isolate);
577 if (*boilerplate == isolate->heap()->undefined_value()) {
578 boilerplate = CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000579 if (boilerplate.is_null()) return Failure::Exception();
580 // Update the functions literal and return the boilerplate.
581 literals->set(literals_index, *boilerplate);
582 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000583 if (JSObject::cast(*boilerplate)->elements()->map() ==
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000584 isolate->heap()->fixed_cow_array_map()) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000585 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000586 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000587 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000588}
589
590
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000591RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSProxy) {
592 ASSERT(args.length() == 2);
593 Object* handler = args[0];
594 Object* prototype = args[1];
595 Object* used_prototype =
596 (prototype->IsJSObject() || prototype->IsJSProxy()) ? prototype
597 : isolate->heap()->null_value();
598 return isolate->heap()->AllocateJSProxy(handler, used_prototype);
599}
600
601
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000602RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateCatchExtensionObject) {
ager@chromium.org32912102009-01-16 10:38:43 +0000603 ASSERT(args.length() == 2);
604 CONVERT_CHECKED(String, key, args[0]);
605 Object* value = args[1];
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000606 ASSERT(!value->IsFailure());
ager@chromium.org32912102009-01-16 10:38:43 +0000607 // Create a catch context extension object.
608 JSFunction* constructor =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000609 isolate->context()->global_context()->
610 context_extension_function();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000611 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000612 { MaybeObject* maybe_object = isolate->heap()->AllocateJSObject(constructor);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000613 if (!maybe_object->ToObject(&object)) return maybe_object;
614 }
ager@chromium.org32912102009-01-16 10:38:43 +0000615 // Assign the exception value to the catch variable and make sure
616 // that the catch variable is DontDelete.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000617 { MaybeObject* maybe_value =
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000618 // Passing non-strict per ECMA-262 5th Ed. 12.14. Catch, bullet #4.
619 JSObject::cast(object)->SetProperty(
620 key, value, DONT_DELETE, kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000621 if (!maybe_value->ToObject(&value)) return maybe_value;
622 }
ager@chromium.org32912102009-01-16 10:38:43 +0000623 return object;
624}
625
626
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000627RUNTIME_FUNCTION(MaybeObject*, Runtime_ClassOf) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000628 NoHandleAllocation ha;
629 ASSERT(args.length() == 1);
630 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000631 if (!obj->IsJSObject()) return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000632 return JSObject::cast(obj)->class_name();
633}
634
ager@chromium.org7c537e22008-10-16 08:43:32 +0000635
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000636RUNTIME_FUNCTION(MaybeObject*, Runtime_IsInPrototypeChain) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000637 NoHandleAllocation ha;
638 ASSERT(args.length() == 2);
639 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
640 Object* O = args[0];
641 Object* V = args[1];
642 while (true) {
643 Object* prototype = V->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000644 if (prototype->IsNull()) return isolate->heap()->false_value();
645 if (O == prototype) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000646 V = prototype;
647 }
648}
649
650
ager@chromium.org9085a012009-05-11 19:22:57 +0000651// Inserts an object as the hidden prototype of another object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000652RUNTIME_FUNCTION(MaybeObject*, Runtime_SetHiddenPrototype) {
ager@chromium.org9085a012009-05-11 19:22:57 +0000653 NoHandleAllocation ha;
654 ASSERT(args.length() == 2);
655 CONVERT_CHECKED(JSObject, jsobject, args[0]);
656 CONVERT_CHECKED(JSObject, proto, args[1]);
657
658 // Sanity checks. The old prototype (that we are replacing) could
659 // theoretically be null, but if it is not null then check that we
660 // didn't already install a hidden prototype here.
661 RUNTIME_ASSERT(!jsobject->GetPrototype()->IsHeapObject() ||
662 !HeapObject::cast(jsobject->GetPrototype())->map()->is_hidden_prototype());
663 RUNTIME_ASSERT(!proto->map()->is_hidden_prototype());
664
665 // Allocate up front before we start altering state in case we get a GC.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000666 Object* map_or_failure;
667 { MaybeObject* maybe_map_or_failure = proto->map()->CopyDropTransitions();
668 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
669 return maybe_map_or_failure;
670 }
671 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000672 Map* new_proto_map = Map::cast(map_or_failure);
673
lrn@chromium.org303ada72010-10-27 09:33:13 +0000674 { MaybeObject* maybe_map_or_failure = jsobject->map()->CopyDropTransitions();
675 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
676 return maybe_map_or_failure;
677 }
678 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000679 Map* new_map = Map::cast(map_or_failure);
680
681 // Set proto's prototype to be the old prototype of the object.
682 new_proto_map->set_prototype(jsobject->GetPrototype());
683 proto->set_map(new_proto_map);
684 new_proto_map->set_is_hidden_prototype();
685
686 // Set the object's prototype to proto.
687 new_map->set_prototype(proto);
688 jsobject->set_map(new_map);
689
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000690 return isolate->heap()->undefined_value();
ager@chromium.org9085a012009-05-11 19:22:57 +0000691}
692
693
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000694RUNTIME_FUNCTION(MaybeObject*, Runtime_IsConstructCall) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000695 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +0000696 ASSERT(args.length() == 0);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000697 JavaScriptFrameIterator it(isolate);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000698 return isolate->heap()->ToBoolean(it.frame()->IsConstructor());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000699}
700
701
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000702// Recursively traverses hidden prototypes if property is not found
703static void GetOwnPropertyImplementation(JSObject* obj,
704 String* name,
705 LookupResult* result) {
706 obj->LocalLookupRealNamedProperty(name, result);
707
708 if (!result->IsProperty()) {
709 Object* proto = obj->GetPrototype();
710 if (proto->IsJSObject() &&
711 JSObject::cast(proto)->map()->is_hidden_prototype())
712 GetOwnPropertyImplementation(JSObject::cast(proto),
713 name, result);
714 }
715}
716
717
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000718static bool CheckAccessException(LookupResult* result,
719 v8::AccessType access_type) {
720 if (result->type() == CALLBACKS) {
721 Object* callback = result->GetCallbackObject();
722 if (callback->IsAccessorInfo()) {
723 AccessorInfo* info = AccessorInfo::cast(callback);
724 bool can_access =
725 (access_type == v8::ACCESS_HAS &&
726 (info->all_can_read() || info->all_can_write())) ||
727 (access_type == v8::ACCESS_GET && info->all_can_read()) ||
728 (access_type == v8::ACCESS_SET && info->all_can_write());
729 return can_access;
730 }
731 }
732
733 return false;
734}
735
736
737static bool CheckAccess(JSObject* obj,
738 String* name,
739 LookupResult* result,
740 v8::AccessType access_type) {
741 ASSERT(result->IsProperty());
742
743 JSObject* holder = result->holder();
744 JSObject* current = obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000745 Isolate* isolate = obj->GetIsolate();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000746 while (true) {
747 if (current->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000748 !isolate->MayNamedAccess(current, name, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000749 // Access check callback denied the access, but some properties
750 // can have a special permissions which override callbacks descision
751 // (currently see v8::AccessControl).
752 break;
753 }
754
755 if (current == holder) {
756 return true;
757 }
758
759 current = JSObject::cast(current->GetPrototype());
760 }
761
762 // API callbacks can have per callback access exceptions.
763 switch (result->type()) {
764 case CALLBACKS: {
765 if (CheckAccessException(result, access_type)) {
766 return true;
767 }
768 break;
769 }
770 case INTERCEPTOR: {
771 // If the object has an interceptor, try real named properties.
772 // Overwrite the result to fetch the correct property later.
773 holder->LookupRealNamedProperty(name, result);
774 if (result->IsProperty()) {
775 if (CheckAccessException(result, access_type)) {
776 return true;
777 }
778 }
779 break;
780 }
781 default:
782 break;
783 }
784
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000785 isolate->ReportFailedAccessCheck(current, access_type);
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000786 return false;
787}
788
789
790// TODO(1095): we should traverse hidden prototype hierachy as well.
791static bool CheckElementAccess(JSObject* obj,
792 uint32_t index,
793 v8::AccessType access_type) {
794 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000795 !obj->GetIsolate()->MayIndexedAccess(obj, index, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000796 return false;
797 }
798
799 return true;
800}
801
802
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000803// Enumerator used as indices into the array returned from GetOwnProperty
804enum PropertyDescriptorIndices {
805 IS_ACCESSOR_INDEX,
806 VALUE_INDEX,
807 GETTER_INDEX,
808 SETTER_INDEX,
809 WRITABLE_INDEX,
810 ENUMERABLE_INDEX,
811 CONFIGURABLE_INDEX,
812 DESCRIPTOR_SIZE
813};
814
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000815// Returns an array with the property description:
816// if args[1] is not a property on args[0]
817// returns undefined
818// if args[1] is a data property on args[0]
819// [false, value, Writeable, Enumerable, Configurable]
820// if args[1] is an accessor on args[0]
821// [true, GetFunction, SetFunction, Enumerable, Configurable]
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000822RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOwnProperty) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000823 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000824 Heap* heap = isolate->heap();
825 HandleScope scope(isolate);
826 Handle<FixedArray> elms = isolate->factory()->NewFixedArray(DESCRIPTOR_SIZE);
827 Handle<JSArray> desc = isolate->factory()->NewJSArrayWithElements(elms);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000828 LookupResult result;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000829 CONVERT_ARG_CHECKED(JSObject, obj, 0);
830 CONVERT_ARG_CHECKED(String, name, 1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000831
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000832 // This could be an element.
833 uint32_t index;
834 if (name->AsArrayIndex(&index)) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000835 switch (obj->HasLocalElement(index)) {
836 case JSObject::UNDEFINED_ELEMENT:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000837 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000838
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000839 case JSObject::STRING_CHARACTER_ELEMENT: {
840 // Special handling of string objects according to ECMAScript 5
841 // 15.5.5.2. Note that this might be a string object with elements
842 // other than the actual string value. This is covered by the
843 // subsequent cases.
844 Handle<JSValue> js_value = Handle<JSValue>::cast(obj);
845 Handle<String> str(String::cast(js_value->value()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000846 Handle<String> substr = SubString(str, index, index + 1, NOT_TENURED);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000847
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000848 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000849 elms->set(VALUE_INDEX, *substr);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000850 elms->set(WRITABLE_INDEX, heap->false_value());
851 elms->set(ENUMERABLE_INDEX, heap->false_value());
852 elms->set(CONFIGURABLE_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000853 return *desc;
854 }
855
856 case JSObject::INTERCEPTED_ELEMENT:
857 case JSObject::FAST_ELEMENT: {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000858 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000859 Handle<Object> value = GetElement(obj, index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000860 RETURN_IF_EMPTY_HANDLE(isolate, value);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000861 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000862 elms->set(WRITABLE_INDEX, heap->true_value());
863 elms->set(ENUMERABLE_INDEX, heap->true_value());
864 elms->set(CONFIGURABLE_INDEX, heap->true_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000865 return *desc;
866 }
867
868 case JSObject::DICTIONARY_ELEMENT: {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000869 Handle<JSObject> holder = obj;
870 if (obj->IsJSGlobalProxy()) {
871 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000872 if (proto->IsNull()) return heap->undefined_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000873 ASSERT(proto->IsJSGlobalObject());
874 holder = Handle<JSObject>(JSObject::cast(proto));
875 }
876 NumberDictionary* dictionary = holder->element_dictionary();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000877 int entry = dictionary->FindEntry(index);
878 ASSERT(entry != NumberDictionary::kNotFound);
879 PropertyDetails details = dictionary->DetailsAt(entry);
880 switch (details.type()) {
881 case CALLBACKS: {
882 // This is an accessor property with getter and/or setter.
883 FixedArray* callbacks =
884 FixedArray::cast(dictionary->ValueAt(entry));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000885 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000886 if (CheckElementAccess(*obj, index, v8::ACCESS_GET)) {
887 elms->set(GETTER_INDEX, callbacks->get(0));
888 }
889 if (CheckElementAccess(*obj, index, v8::ACCESS_SET)) {
890 elms->set(SETTER_INDEX, callbacks->get(1));
891 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000892 break;
893 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000894 case NORMAL: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000895 // This is a data property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000896 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000897 Handle<Object> value = GetElement(obj, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000898 ASSERT(!value.is_null());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000899 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000900 elms->set(WRITABLE_INDEX, heap->ToBoolean(!details.IsReadOnly()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000901 break;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000902 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000903 default:
904 UNREACHABLE();
905 break;
906 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000907 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!details.IsDontEnum()));
908 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!details.IsDontDelete()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000909 return *desc;
910 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000911 }
912 }
913
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000914 // Use recursive implementation to also traverse hidden prototypes
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000915 GetOwnPropertyImplementation(*obj, *name, &result);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000916
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000917 if (!result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000918 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000919 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000920
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000921 if (!CheckAccess(*obj, *name, &result, v8::ACCESS_HAS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000922 return heap->false_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000923 }
924
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000925 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!result.IsDontEnum()));
926 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!result.IsDontDelete()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000927
928 bool is_js_accessor = (result.type() == CALLBACKS) &&
929 (result.GetCallbackObject()->IsFixedArray());
930
931 if (is_js_accessor) {
932 // __defineGetter__/__defineSetter__ callback.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000933 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000934
935 FixedArray* structure = FixedArray::cast(result.GetCallbackObject());
936 if (CheckAccess(*obj, *name, &result, v8::ACCESS_GET)) {
937 elms->set(GETTER_INDEX, structure->get(0));
938 }
939 if (CheckAccess(*obj, *name, &result, v8::ACCESS_SET)) {
940 elms->set(SETTER_INDEX, structure->get(1));
941 }
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000942 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000943 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
944 elms->set(WRITABLE_INDEX, heap->ToBoolean(!result.IsReadOnly()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000945
946 PropertyAttributes attrs;
947 Object* value;
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000948 // GetProperty will check access and report any violations.
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000949 { MaybeObject* maybe_value = obj->GetProperty(*obj, &result, *name, &attrs);
950 if (!maybe_value->ToObject(&value)) return maybe_value;
951 }
952 elms->set(VALUE_INDEX, value);
953 }
954
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000955 return *desc;
956}
957
958
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000959RUNTIME_FUNCTION(MaybeObject*, Runtime_PreventExtensions) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000960 ASSERT(args.length() == 1);
961 CONVERT_CHECKED(JSObject, obj, args[0]);
962 return obj->PreventExtensions();
963}
964
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000965
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000966RUNTIME_FUNCTION(MaybeObject*, Runtime_IsExtensible) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000967 ASSERT(args.length() == 1);
968 CONVERT_CHECKED(JSObject, obj, args[0]);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000969 if (obj->IsJSGlobalProxy()) {
970 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000971 if (proto->IsNull()) return isolate->heap()->false_value();
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000972 ASSERT(proto->IsJSGlobalObject());
973 obj = JSObject::cast(proto);
974 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000975 return obj->map()->is_extensible() ? isolate->heap()->true_value()
976 : isolate->heap()->false_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000977}
978
979
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000980RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000981 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000982 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000983 CONVERT_ARG_CHECKED(JSRegExp, re, 0);
984 CONVERT_ARG_CHECKED(String, pattern, 1);
985 CONVERT_ARG_CHECKED(String, flags, 2);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000986 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags);
987 if (result.is_null()) return Failure::Exception();
988 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000989}
990
991
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000992RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateApiFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000993 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000994 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000995 CONVERT_ARG_CHECKED(FunctionTemplateInfo, data, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000996 return *isolate->factory()->CreateApiFunction(data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000997}
998
999
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001000RUNTIME_FUNCTION(MaybeObject*, Runtime_IsTemplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001001 ASSERT(args.length() == 1);
1002 Object* arg = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001003 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001004 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001005}
1006
1007
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001008RUNTIME_FUNCTION(MaybeObject*, Runtime_GetTemplateField) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001009 ASSERT(args.length() == 2);
1010 CONVERT_CHECKED(HeapObject, templ, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001011 CONVERT_CHECKED(Smi, field, args[1]);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001012 int index = field->value();
1013 int offset = index * kPointerSize + HeapObject::kHeaderSize;
1014 InstanceType type = templ->map()->instance_type();
1015 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
1016 type == OBJECT_TEMPLATE_INFO_TYPE);
1017 RUNTIME_ASSERT(offset > 0);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001018 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001019 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
1020 } else {
1021 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
1022 }
1023 return *HeapObject::RawField(templ, offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001024}
1025
1026
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001027RUNTIME_FUNCTION(MaybeObject*, Runtime_DisableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001028 ASSERT(args.length() == 1);
1029 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001030 Map* old_map = object->map();
1031 bool needs_access_checks = old_map->is_access_check_needed();
1032 if (needs_access_checks) {
1033 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001034 Object* new_map;
1035 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1036 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1037 }
ager@chromium.org32912102009-01-16 10:38:43 +00001038
1039 Map::cast(new_map)->set_is_access_check_needed(false);
1040 object->set_map(Map::cast(new_map));
1041 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001042 return needs_access_checks ? isolate->heap()->true_value()
1043 : isolate->heap()->false_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001044}
1045
1046
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001047RUNTIME_FUNCTION(MaybeObject*, Runtime_EnableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001048 ASSERT(args.length() == 1);
1049 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001050 Map* old_map = object->map();
1051 if (!old_map->is_access_check_needed()) {
1052 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001053 Object* new_map;
1054 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1055 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1056 }
ager@chromium.org32912102009-01-16 10:38:43 +00001057
1058 Map::cast(new_map)->set_is_access_check_needed(true);
1059 object->set_map(Map::cast(new_map));
1060 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001061 return isolate->heap()->undefined_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001062}
1063
1064
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001065static Failure* ThrowRedeclarationError(Isolate* isolate,
1066 const char* type,
1067 Handle<String> name) {
1068 HandleScope scope(isolate);
1069 Handle<Object> type_handle =
1070 isolate->factory()->NewStringFromAscii(CStrVector(type));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001071 Handle<Object> args[2] = { type_handle, name };
1072 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001073 isolate->factory()->NewTypeError("redeclaration", HandleVector(args, 2));
1074 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001075}
1076
1077
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001078RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001079 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001080 HandleScope scope(isolate);
1081 Handle<GlobalObject> global = Handle<GlobalObject>(
1082 isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001083
ager@chromium.org3811b432009-10-28 14:53:37 +00001084 Handle<Context> context = args.at<Context>(0);
1085 CONVERT_ARG_CHECKED(FixedArray, pairs, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001086 bool is_eval = Smi::cast(args[2])->value() == 1;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001087 StrictModeFlag strict_mode =
1088 static_cast<StrictModeFlag>(Smi::cast(args[3])->value());
1089 ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001090
1091 // Compute the property attributes. According to ECMA-262, section
1092 // 13, page 71, the property must be read-only and
1093 // non-deletable. However, neither SpiderMonkey nor KJS creates the
1094 // property as read-only, so we don't either.
1095 PropertyAttributes base = is_eval ? NONE : DONT_DELETE;
1096
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001097 // Traverse the name/value pairs and set the properties.
1098 int length = pairs->length();
1099 for (int i = 0; i < length; i += 2) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001100 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001101 Handle<String> name(String::cast(pairs->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001102 Handle<Object> value(pairs->get(i + 1), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001103
1104 // We have to declare a global const property. To capture we only
1105 // assign to it when evaluating the assignment for "const x =
1106 // <expr>" the initial value is the hole.
1107 bool is_const_property = value->IsTheHole();
1108
1109 if (value->IsUndefined() || is_const_property) {
1110 // Lookup the property in the global object, and don't set the
1111 // value of the variable if the property is already there.
1112 LookupResult lookup;
1113 global->Lookup(*name, &lookup);
1114 if (lookup.IsProperty()) {
1115 // Determine if the property is local by comparing the holder
1116 // against the global object. The information will be used to
1117 // avoid throwing re-declaration errors when declaring
1118 // variables or constants that exist in the prototype chain.
1119 bool is_local = (*global == lookup.holder());
1120 // Get the property attributes and determine if the property is
1121 // read-only.
1122 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
1123 bool is_read_only = (attributes & READ_ONLY) != 0;
1124 if (lookup.type() == INTERCEPTOR) {
1125 // If the interceptor says the property is there, we
1126 // just return undefined without overwriting the property.
1127 // Otherwise, we continue to setting the property.
1128 if (attributes != ABSENT) {
1129 // Check if the existing property conflicts with regards to const.
1130 if (is_local && (is_read_only || is_const_property)) {
1131 const char* type = (is_read_only) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001132 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001133 };
1134 // The property already exists without conflicting: Go to
1135 // the next declaration.
1136 continue;
1137 }
1138 // Fall-through and introduce the absent property by using
1139 // SetProperty.
1140 } else {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001141 // For const properties, we treat a callback with this name
1142 // even in the prototype as a conflicting declaration.
1143 if (is_const_property && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001144 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001145 }
1146 // Otherwise, we check for locally conflicting declarations.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001147 if (is_local && (is_read_only || is_const_property)) {
1148 const char* type = (is_read_only) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001149 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001150 }
1151 // The property already exists without conflicting: Go to
1152 // the next declaration.
1153 continue;
1154 }
1155 }
1156 } else {
1157 // Copy the function and update its context. Use it as value.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001158 Handle<SharedFunctionInfo> shared =
1159 Handle<SharedFunctionInfo>::cast(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001160 Handle<JSFunction> function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001161 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
1162 context,
1163 TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001164 value = function;
1165 }
1166
1167 LookupResult lookup;
1168 global->LocalLookup(*name, &lookup);
1169
1170 PropertyAttributes attributes = is_const_property
1171 ? static_cast<PropertyAttributes>(base | READ_ONLY)
1172 : base;
1173
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001174 // There's a local property that we need to overwrite because
1175 // we're either declaring a function or there's an interceptor
1176 // that claims the property is absent.
1177 //
1178 // Check for conflicting re-declarations. We cannot have
1179 // conflicting types in case of intercepted properties because
1180 // they are absent.
1181 if (lookup.IsProperty() &&
1182 (lookup.type() != INTERCEPTOR) &&
1183 (lookup.IsReadOnly() || is_const_property)) {
1184 const char* type = (lookup.IsReadOnly()) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001185 return ThrowRedeclarationError(isolate, type, name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001186 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001187
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001188 // Safari does not allow the invocation of callback setters for
1189 // function declarations. To mimic this behavior, we do not allow
1190 // the invocation of setters for function values. This makes a
1191 // difference for global functions with the same names as event
1192 // handlers such as "function onload() {}". Firefox does call the
1193 // onload setter in those case and Safari does not. We follow
1194 // Safari for compatibility.
1195 if (value->IsJSFunction()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001196 // Do not change DONT_DELETE to false from true.
1197 if (lookup.IsProperty() && (lookup.type() != INTERCEPTOR)) {
1198 attributes = static_cast<PropertyAttributes>(
1199 attributes | (lookup.GetAttributes() & DONT_DELETE));
1200 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001201 RETURN_IF_EMPTY_HANDLE(isolate,
1202 SetLocalPropertyIgnoreAttributes(global,
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001203 name,
1204 value,
1205 attributes));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001206 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001207 RETURN_IF_EMPTY_HANDLE(isolate,
1208 SetProperty(global,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001209 name,
1210 value,
1211 attributes,
1212 strict_mode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001213 }
1214 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001215
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001216 ASSERT(!isolate->has_pending_exception());
1217 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001218}
1219
1220
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001221RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001222 HandleScope scope(isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001223 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001224
ager@chromium.org7c537e22008-10-16 08:43:32 +00001225 CONVERT_ARG_CHECKED(Context, context, 0);
1226 Handle<String> name(String::cast(args[1]));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001227 PropertyAttributes mode =
ager@chromium.org7c537e22008-10-16 08:43:32 +00001228 static_cast<PropertyAttributes>(Smi::cast(args[2])->value());
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001229 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001230 Handle<Object> initial_value(args[3], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001231
1232 // Declarations are always done in the function context.
1233 context = Handle<Context>(context->fcontext());
1234
1235 int index;
1236 PropertyAttributes attributes;
1237 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001238 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001239 context->Lookup(name, flags, &index, &attributes);
1240
1241 if (attributes != ABSENT) {
1242 // The name was declared before; check for conflicting
1243 // re-declarations: This is similar to the code in parser.cc in
1244 // the AstBuildingParser::Declare function.
1245 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
1246 // Functions are not read-only.
1247 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
1248 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001249 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001250 }
1251
1252 // Initialize it if necessary.
1253 if (*initial_value != NULL) {
1254 if (index >= 0) {
1255 // The variable or constant context slot should always be in
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001256 // the function context or the arguments object.
1257 if (holder->IsContext()) {
1258 ASSERT(holder.is_identical_to(context));
1259 if (((attributes & READ_ONLY) == 0) ||
1260 context->get(index)->IsTheHole()) {
1261 context->set(index, *initial_value);
1262 }
1263 } else {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001264 // The holder is an arguments object.
1265 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001266 Handle<Object> result = SetElement(arguments, index, initial_value,
1267 kNonStrictMode);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001268 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001269 }
1270 } else {
1271 // Slow case: The property is not in the FixedArray part of the context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001272 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001273 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001274 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001275 SetProperty(context_ext, name, initial_value,
1276 mode, kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001277 }
1278 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001279
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001280 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001281 // The property is not in the function context. It needs to be
1282 // "declared" in the function context's extension context, or in the
1283 // global context.
1284 Handle<JSObject> context_ext;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001285 if (context->has_extension()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001286 // The function context's extension context exists - use it.
1287 context_ext = Handle<JSObject>(context->extension());
1288 } else {
1289 // The function context's extension context does not exists - allocate
1290 // it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001291 context_ext = isolate->factory()->NewJSObject(
1292 isolate->context_extension_function());
ager@chromium.org7c537e22008-10-16 08:43:32 +00001293 // And store it in the extension slot.
1294 context->set_extension(*context_ext);
1295 }
1296 ASSERT(*context_ext != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001297
ager@chromium.org7c537e22008-10-16 08:43:32 +00001298 // Declare the property by setting it to the initial value if provided,
1299 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
1300 // constant declarations).
1301 ASSERT(!context_ext->HasLocalProperty(*name));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001302 Handle<Object> value(isolate->heap()->undefined_value(), isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001303 if (*initial_value != NULL) value = initial_value;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001304 // Declaring a const context slot is a conflicting declaration if
1305 // there is a callback with that name in a prototype. It is
1306 // allowed to introduce const variables in
1307 // JSContextExtensionObjects. They are treated specially in
1308 // SetProperty and no setters are invoked for those since they are
1309 // not real JSObjects.
1310 if (initial_value->IsTheHole() &&
1311 !context_ext->IsJSContextExtensionObject()) {
1312 LookupResult lookup;
1313 context_ext->Lookup(*name, &lookup);
1314 if (lookup.IsProperty() && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001315 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001316 }
1317 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001318 RETURN_IF_EMPTY_HANDLE(isolate,
1319 SetProperty(context_ext, name, value, mode,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001320 kNonStrictMode));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001321 }
1322
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001323 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001324}
1325
1326
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001327RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001328 NoHandleAllocation nha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001329 // args[0] == name
1330 // args[1] == strict_mode
1331 // args[2] == value (optional)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001332
1333 // Determine if we need to assign to the variable if it already
1334 // exists (based on the number of arguments).
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001335 RUNTIME_ASSERT(args.length() == 2 || args.length() == 3);
1336 bool assign = args.length() == 3;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001337
1338 CONVERT_ARG_CHECKED(String, name, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001339 GlobalObject* global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001340 RUNTIME_ASSERT(args[1]->IsSmi());
1341 StrictModeFlag strict_mode =
1342 static_cast<StrictModeFlag>(Smi::cast(args[1])->value());
1343 ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001344
1345 // According to ECMA-262, section 12.2, page 62, the property must
1346 // not be deletable.
1347 PropertyAttributes attributes = DONT_DELETE;
1348
1349 // Lookup the property locally in the global object. If it isn't
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001350 // there, there is a property with this name in the prototype chain.
1351 // We follow Safari and Firefox behavior and only set the property
1352 // locally if there is an explicit initialization value that we have
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001353 // to assign to the property.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001354 // Note that objects can have hidden prototypes, so we need to traverse
1355 // the whole chain of hidden prototypes to do a 'local' lookup.
1356 JSObject* real_holder = global;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001357 LookupResult lookup;
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001358 while (true) {
1359 real_holder->LocalLookup(*name, &lookup);
1360 if (lookup.IsProperty()) {
1361 // Determine if this is a redeclaration of something read-only.
1362 if (lookup.IsReadOnly()) {
1363 // If we found readonly property on one of hidden prototypes,
1364 // just shadow it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001365 if (real_holder != isolate->context()->global()) break;
1366 return ThrowRedeclarationError(isolate, "const", name);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001367 }
1368
1369 // Determine if this is a redeclaration of an intercepted read-only
1370 // property and figure out if the property exists at all.
1371 bool found = true;
1372 PropertyType type = lookup.type();
1373 if (type == INTERCEPTOR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001374 HandleScope handle_scope(isolate);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001375 Handle<JSObject> holder(real_holder);
1376 PropertyAttributes intercepted = holder->GetPropertyAttribute(*name);
1377 real_holder = *holder;
1378 if (intercepted == ABSENT) {
1379 // The interceptor claims the property isn't there. We need to
1380 // make sure to introduce it.
1381 found = false;
1382 } else if ((intercepted & READ_ONLY) != 0) {
1383 // The property is present, but read-only. Since we're trying to
1384 // overwrite it with a variable declaration we must throw a
1385 // re-declaration error. However if we found readonly property
1386 // on one of hidden prototypes, just shadow it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001387 if (real_holder != isolate->context()->global()) break;
1388 return ThrowRedeclarationError(isolate, "const", name);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001389 }
1390 }
1391
1392 if (found && !assign) {
1393 // The global property is there and we're not assigning any value
1394 // to it. Just return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001395 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001396 }
1397
1398 // Assign the value (or undefined) to the property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001399 Object* value = (assign) ? args[2] : isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001400 return real_holder->SetProperty(
1401 &lookup, *name, value, attributes, strict_mode);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001402 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001403
1404 Object* proto = real_holder->GetPrototype();
1405 if (!proto->IsJSObject())
1406 break;
1407
1408 if (!JSObject::cast(proto)->map()->is_hidden_prototype())
1409 break;
1410
1411 real_holder = JSObject::cast(proto);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001412 }
1413
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001414 global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001415 if (assign) {
1416 return global->SetProperty(*name, args[2], attributes, strict_mode);
1417 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001418 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001419}
1420
1421
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001422RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001423 // All constants are declared with an initial value. The name
1424 // of the constant is the first argument and the initial value
1425 // is the second.
1426 RUNTIME_ASSERT(args.length() == 2);
1427 CONVERT_ARG_CHECKED(String, name, 0);
1428 Handle<Object> value = args.at<Object>(1);
1429
1430 // Get the current global object from top.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001431 GlobalObject* global = isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001432
1433 // According to ECMA-262, section 12.2, page 62, the property must
1434 // not be deletable. Since it's a const, it must be READ_ONLY too.
1435 PropertyAttributes attributes =
1436 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
1437
1438 // Lookup the property locally in the global object. If it isn't
1439 // there, we add the property and take special precautions to always
1440 // add it as a local property even in case of callbacks in the
1441 // prototype chain (this rules out using SetProperty).
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001442 // We use SetLocalPropertyIgnoreAttributes instead
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001443 LookupResult lookup;
1444 global->LocalLookup(*name, &lookup);
1445 if (!lookup.IsProperty()) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001446 return global->SetLocalPropertyIgnoreAttributes(*name,
1447 *value,
1448 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001449 }
1450
1451 // Determine if this is a redeclaration of something not
1452 // read-only. In case the result is hidden behind an interceptor we
1453 // need to ask it for the property attributes.
1454 if (!lookup.IsReadOnly()) {
1455 if (lookup.type() != INTERCEPTOR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001456 return ThrowRedeclarationError(isolate, "var", name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001457 }
1458
1459 PropertyAttributes intercepted = global->GetPropertyAttribute(*name);
1460
1461 // Throw re-declaration error if the intercepted property is present
1462 // but not read-only.
1463 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001464 return ThrowRedeclarationError(isolate, "var", name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001465 }
1466
1467 // Restore global object from context (in case of GC) and continue
1468 // with setting the value because the property is either absent or
1469 // read-only. We also have to do redo the lookup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001470 HandleScope handle_scope(isolate);
1471 Handle<GlobalObject> global(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001472
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001473 // BUG 1213575: Handle the case where we have to set a read-only
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001474 // property through an interceptor and only do it if it's
1475 // uninitialized, e.g. the hole. Nirk...
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001476 // Passing non-strict mode because the property is writable.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001477 RETURN_IF_EMPTY_HANDLE(isolate,
1478 SetProperty(global,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001479 name,
1480 value,
1481 attributes,
1482 kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001483 return *value;
1484 }
1485
1486 // Set the value, but only we're assigning the initial value to a
1487 // constant. For now, we determine this by checking if the
1488 // current value is the hole.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001489 // Strict mode handling not needed (const disallowed in strict mode).
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001490 PropertyType type = lookup.type();
1491 if (type == FIELD) {
1492 FixedArray* properties = global->properties();
1493 int index = lookup.GetFieldIndex();
1494 if (properties->get(index)->IsTheHole()) {
1495 properties->set(index, *value);
1496 }
1497 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001498 if (global->GetNormalizedProperty(&lookup)->IsTheHole()) {
1499 global->SetNormalizedProperty(&lookup, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001500 }
1501 } else {
1502 // Ignore re-initialization of constants that have already been
1503 // assigned a function value.
1504 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
1505 }
1506
1507 // Use the set value as the result of the operation.
1508 return *value;
1509}
1510
1511
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001512RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001513 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001514 ASSERT(args.length() == 3);
1515
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001516 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001517 ASSERT(!value->IsTheHole());
1518 CONVERT_ARG_CHECKED(Context, context, 1);
1519 Handle<String> name(String::cast(args[2]));
1520
1521 // Initializations are always done in the function context.
1522 context = Handle<Context>(context->fcontext());
1523
1524 int index;
1525 PropertyAttributes attributes;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001526 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001527 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001528 context->Lookup(name, flags, &index, &attributes);
1529
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001530 // In most situations, the property introduced by the const
1531 // declaration should be present in the context extension object.
1532 // However, because declaration and initialization are separate, the
1533 // property might have been deleted (if it was introduced by eval)
1534 // before we reach the initialization point.
1535 //
1536 // Example:
1537 //
1538 // function f() { eval("delete x; const x;"); }
1539 //
1540 // In that case, the initialization behaves like a normal assignment
1541 // to property 'x'.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001542 if (index >= 0) {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001543 // Property was found in a context.
1544 if (holder->IsContext()) {
1545 // The holder cannot be the function context. If it is, there
1546 // should have been a const redeclaration error when declaring
1547 // the const property.
1548 ASSERT(!holder.is_identical_to(context));
1549 if ((attributes & READ_ONLY) == 0) {
1550 Handle<Context>::cast(holder)->set(index, *value);
1551 }
1552 } else {
1553 // The holder is an arguments object.
1554 ASSERT((attributes & READ_ONLY) == 0);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001555 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001556 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001557 isolate,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001558 SetElement(arguments, index, value, kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001559 }
1560 return *value;
1561 }
1562
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001563 // The property could not be found, we introduce it in the global
1564 // context.
1565 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001566 Handle<JSObject> global = Handle<JSObject>(
1567 isolate->context()->global());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001568 // Strict mode not needed (const disallowed in strict mode).
1569 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001570 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001571 SetProperty(global, name, value, NONE, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001572 return *value;
1573 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001574
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001575 // The property was present in a context extension object.
1576 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001577
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001578 if (*context_ext == context->extension()) {
1579 // This is the property that was introduced by the const
1580 // declaration. Set it if it hasn't been set before. NOTE: We
1581 // cannot use GetProperty() to get the current value as it
1582 // 'unholes' the value.
1583 LookupResult lookup;
1584 context_ext->LocalLookupRealNamedProperty(*name, &lookup);
1585 ASSERT(lookup.IsProperty()); // the property was declared
1586 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
1587
1588 PropertyType type = lookup.type();
1589 if (type == FIELD) {
1590 FixedArray* properties = context_ext->properties();
1591 int index = lookup.GetFieldIndex();
1592 if (properties->get(index)->IsTheHole()) {
1593 properties->set(index, *value);
1594 }
1595 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001596 if (context_ext->GetNormalizedProperty(&lookup)->IsTheHole()) {
1597 context_ext->SetNormalizedProperty(&lookup, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001598 }
1599 } else {
1600 // We should not reach here. Any real, named property should be
1601 // either a field or a dictionary slot.
1602 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001603 }
1604 } else {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001605 // The property was found in a different context extension object.
1606 // Set it if it is not a read-only property.
1607 if ((attributes & READ_ONLY) == 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001608 // Strict mode not needed (const disallowed in strict mode).
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001609 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001610 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001611 SetProperty(context_ext, name, value, attributes, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001612 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001613 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001614
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001615 return *value;
1616}
1617
1618
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001619RUNTIME_FUNCTION(MaybeObject*,
1620 Runtime_OptimizeObjectForAddingMultipleProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001621 HandleScope scope(isolate);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001622 ASSERT(args.length() == 2);
1623 CONVERT_ARG_CHECKED(JSObject, object, 0);
1624 CONVERT_SMI_CHECKED(properties, args[1]);
1625 if (object->HasFastProperties()) {
1626 NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
1627 }
1628 return *object;
1629}
1630
1631
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001632RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExec) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001633 HandleScope scope(isolate);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001634 ASSERT(args.length() == 4);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001635 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
1636 CONVERT_ARG_CHECKED(String, subject, 1);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001637 // Due to the way the JS calls are constructed this must be less than the
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001638 // length of a string, i.e. it is always a Smi. We check anyway for security.
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001639 CONVERT_SMI_CHECKED(index, args[2]);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001640 CONVERT_ARG_CHECKED(JSArray, last_match_info, 3);
ager@chromium.org41826e72009-03-30 13:30:57 +00001641 RUNTIME_ASSERT(last_match_info->HasFastElements());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001642 RUNTIME_ASSERT(index >= 0);
1643 RUNTIME_ASSERT(index <= subject->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001644 isolate->counters()->regexp_entry_runtime()->Increment();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001645 Handle<Object> result = RegExpImpl::Exec(regexp,
1646 subject,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001647 index,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001648 last_match_info);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001649 if (result.is_null()) return Failure::Exception();
1650 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001651}
1652
1653
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001654RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpConstructResult) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001655 ASSERT(args.length() == 3);
1656 CONVERT_SMI_CHECKED(elements_count, args[0]);
1657 if (elements_count > JSArray::kMaxFastElementsLength) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001658 return isolate->ThrowIllegalOperation();
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001659 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00001660 Object* new_object;
1661 { MaybeObject* maybe_new_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001662 isolate->heap()->AllocateFixedArrayWithHoles(elements_count);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001663 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1664 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001665 FixedArray* elements = FixedArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001666 { MaybeObject* maybe_new_object = isolate->heap()->AllocateRaw(
1667 JSRegExpResult::kSize, NEW_SPACE, OLD_POINTER_SPACE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001668 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1669 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001670 {
1671 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001672 HandleScope scope(isolate);
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001673 reinterpret_cast<HeapObject*>(new_object)->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001674 set_map(isolate->global_context()->regexp_result_map());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001675 }
1676 JSArray* array = JSArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001677 array->set_properties(isolate->heap()->empty_fixed_array());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001678 array->set_elements(elements);
1679 array->set_length(Smi::FromInt(elements_count));
1680 // Write in-object properties after the length of the array.
1681 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]);
1682 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]);
1683 return array;
1684}
1685
1686
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001687RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpInitializeObject) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00001688 AssertNoAllocation no_alloc;
1689 ASSERT(args.length() == 5);
1690 CONVERT_CHECKED(JSRegExp, regexp, args[0]);
1691 CONVERT_CHECKED(String, source, args[1]);
1692
1693 Object* global = args[2];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001694 if (!global->IsTrue()) global = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001695
1696 Object* ignoreCase = args[3];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001697 if (!ignoreCase->IsTrue()) ignoreCase = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001698
1699 Object* multiline = args[4];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001700 if (!multiline->IsTrue()) multiline = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001701
1702 Map* map = regexp->map();
1703 Object* constructor = map->constructor();
1704 if (constructor->IsJSFunction() &&
1705 JSFunction::cast(constructor)->initial_map() == map) {
1706 // If we still have the original map, set in-object properties directly.
1707 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source);
1708 // TODO(lrn): Consider skipping write barrier on booleans as well.
1709 // Both true and false should be in oldspace at all times.
1710 regexp->InObjectPropertyAtPut(JSRegExp::kGlobalFieldIndex, global);
1711 regexp->InObjectPropertyAtPut(JSRegExp::kIgnoreCaseFieldIndex, ignoreCase);
1712 regexp->InObjectPropertyAtPut(JSRegExp::kMultilineFieldIndex, multiline);
1713 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
1714 Smi::FromInt(0),
1715 SKIP_WRITE_BARRIER);
1716 return regexp;
1717 }
1718
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001719 // Map has changed, so use generic, but slower, method.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001720 PropertyAttributes final =
1721 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
1722 PropertyAttributes writable =
1723 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001724 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +00001725 MaybeObject* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001726 result = regexp->SetLocalPropertyIgnoreAttributes(heap->source_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001727 source,
1728 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001729 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001730 result = regexp->SetLocalPropertyIgnoreAttributes(heap->global_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001731 global,
1732 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001733 ASSERT(!result->IsFailure());
1734 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001735 regexp->SetLocalPropertyIgnoreAttributes(heap->ignore_case_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001736 ignoreCase,
1737 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001738 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001739 result = regexp->SetLocalPropertyIgnoreAttributes(heap->multiline_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001740 multiline,
1741 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001742 ASSERT(!result->IsFailure());
1743 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001744 regexp->SetLocalPropertyIgnoreAttributes(heap->last_index_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001745 Smi::FromInt(0),
1746 writable);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001747 ASSERT(!result->IsFailure());
1748 USE(result);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001749 return regexp;
1750}
1751
1752
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001753RUNTIME_FUNCTION(MaybeObject*, Runtime_FinishArrayPrototypeSetup) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001754 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001755 ASSERT(args.length() == 1);
1756 CONVERT_ARG_CHECKED(JSArray, prototype, 0);
1757 // This is necessary to enable fast checks for absence of elements
1758 // on Array.prototype and below.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001759 prototype->set_elements(isolate->heap()->empty_fixed_array());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001760 return Smi::FromInt(0);
1761}
1762
1763
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001764static Handle<JSFunction> InstallBuiltin(Isolate* isolate,
1765 Handle<JSObject> holder,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001766 const char* name,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001767 Builtins::Name builtin_name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001768 Handle<String> key = isolate->factory()->LookupAsciiSymbol(name);
1769 Handle<Code> code(isolate->builtins()->builtin(builtin_name));
1770 Handle<JSFunction> optimized =
1771 isolate->factory()->NewFunction(key,
1772 JS_OBJECT_TYPE,
1773 JSObject::kHeaderSize,
1774 code,
1775 false);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001776 optimized->shared()->DontAdaptArguments();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001777 SetProperty(holder, key, optimized, NONE, kStrictMode);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001778 return optimized;
1779}
1780
1781
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001782RUNTIME_FUNCTION(MaybeObject*, Runtime_SpecialArrayFunctions) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001783 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001784 ASSERT(args.length() == 1);
1785 CONVERT_ARG_CHECKED(JSObject, holder, 0);
1786
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001787 InstallBuiltin(isolate, holder, "pop", Builtins::kArrayPop);
1788 InstallBuiltin(isolate, holder, "push", Builtins::kArrayPush);
1789 InstallBuiltin(isolate, holder, "shift", Builtins::kArrayShift);
1790 InstallBuiltin(isolate, holder, "unshift", Builtins::kArrayUnshift);
1791 InstallBuiltin(isolate, holder, "slice", Builtins::kArraySlice);
1792 InstallBuiltin(isolate, holder, "splice", Builtins::kArraySplice);
1793 InstallBuiltin(isolate, holder, "concat", Builtins::kArrayConcat);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001794
1795 return *holder;
1796}
1797
1798
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001799RUNTIME_FUNCTION(MaybeObject*, Runtime_GetGlobalReceiver) {
ager@chromium.org357bf652010-04-12 11:30:10 +00001800 // Returns a real global receiver, not one of builtins object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001801 Context* global_context =
1802 isolate->context()->global()->global_context();
ager@chromium.org357bf652010-04-12 11:30:10 +00001803 return global_context->global()->global_receiver();
1804}
1805
1806
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001807RUNTIME_FUNCTION(MaybeObject*, Runtime_MaterializeRegExpLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001808 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001809 ASSERT(args.length() == 4);
1810 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
1811 int index = Smi::cast(args[1])->value();
1812 Handle<String> pattern = args.at<String>(2);
1813 Handle<String> flags = args.at<String>(3);
1814
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001815 // Get the RegExp function from the context in the literals array.
1816 // This is the RegExp function from the context in which the
1817 // function was created. We do not use the RegExp function from the
1818 // current global context because this might be the RegExp function
1819 // from another context which we should not have access to.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001820 Handle<JSFunction> constructor =
ager@chromium.org236ad962008-09-25 09:45:57 +00001821 Handle<JSFunction>(
1822 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001823 // Compute the regular expression literal.
1824 bool has_pending_exception;
1825 Handle<Object> regexp =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001826 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
1827 &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001828 if (has_pending_exception) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001829 ASSERT(isolate->has_pending_exception());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001830 return Failure::Exception();
1831 }
1832 literals->set(index, *regexp);
1833 return *regexp;
1834}
1835
1836
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001837RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001838 NoHandleAllocation ha;
1839 ASSERT(args.length() == 1);
1840
1841 CONVERT_CHECKED(JSFunction, f, args[0]);
1842 return f->shared()->name();
1843}
1844
1845
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001846RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetName) {
ager@chromium.org236ad962008-09-25 09:45:57 +00001847 NoHandleAllocation ha;
1848 ASSERT(args.length() == 2);
1849
1850 CONVERT_CHECKED(JSFunction, f, args[0]);
1851 CONVERT_CHECKED(String, name, args[1]);
1852 f->shared()->set_name(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001853 return isolate->heap()->undefined_value();
ager@chromium.org236ad962008-09-25 09:45:57 +00001854}
1855
1856
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001857RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionRemovePrototype) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001858 NoHandleAllocation ha;
1859 ASSERT(args.length() == 1);
1860
1861 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001862 Object* obj = f->RemovePrototype();
1863 if (obj->IsFailure()) return obj;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001864
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001865 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001866}
1867
1868
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001869RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001870 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001871 ASSERT(args.length() == 1);
1872
1873 CONVERT_CHECKED(JSFunction, fun, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001874 Handle<Object> script = Handle<Object>(fun->shared()->script(), isolate);
1875 if (!script->IsScript()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001876
1877 return *GetScriptWrapper(Handle<Script>::cast(script));
1878}
1879
1880
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001881RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetSourceCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001882 NoHandleAllocation ha;
1883 ASSERT(args.length() == 1);
1884
1885 CONVERT_CHECKED(JSFunction, f, args[0]);
1886 return f->shared()->GetSourceCode();
1887}
1888
1889
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001890RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScriptSourcePosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001891 NoHandleAllocation ha;
1892 ASSERT(args.length() == 1);
1893
1894 CONVERT_CHECKED(JSFunction, fun, args[0]);
1895 int pos = fun->shared()->start_position();
1896 return Smi::FromInt(pos);
1897}
1898
1899
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001900RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetPositionForOffset) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001901 ASSERT(args.length() == 2);
1902
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001903 CONVERT_CHECKED(Code, code, args[0]);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001904 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
1905
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001906 RUNTIME_ASSERT(0 <= offset && offset < code->Size());
1907
1908 Address pc = code->address() + offset;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001909 return Smi::FromInt(code->SourcePosition(pc));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001910}
1911
1912
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001913RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetInstanceClassName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001914 NoHandleAllocation ha;
1915 ASSERT(args.length() == 2);
1916
1917 CONVERT_CHECKED(JSFunction, fun, args[0]);
1918 CONVERT_CHECKED(String, name, args[1]);
1919 fun->SetInstanceClassName(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001920 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001921}
1922
1923
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001924RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetLength) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001925 NoHandleAllocation ha;
1926 ASSERT(args.length() == 2);
1927
1928 CONVERT_CHECKED(JSFunction, fun, args[0]);
1929 CONVERT_CHECKED(Smi, length, args[1]);
1930 fun->shared()->set_length(length->value());
1931 return length;
1932}
1933
1934
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001935RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetPrototype) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001936 NoHandleAllocation ha;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001937 ASSERT(args.length() == 2);
1938
1939 CONVERT_CHECKED(JSFunction, fun, args[0]);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001940 ASSERT(fun->should_have_prototype());
lrn@chromium.org303ada72010-10-27 09:33:13 +00001941 Object* obj;
1942 { MaybeObject* maybe_obj =
1943 Accessors::FunctionSetPrototype(fun, args[1], NULL);
1944 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1945 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001946 return args[0]; // return TOS
1947}
1948
1949
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001950RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsAPIFunction) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001951 NoHandleAllocation ha;
1952 ASSERT(args.length() == 1);
1953
1954 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001955 return f->shared()->IsApiFunction() ? isolate->heap()->true_value()
1956 : isolate->heap()->false_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001957}
1958
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001959
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001960RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsBuiltin) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001961 NoHandleAllocation ha;
1962 ASSERT(args.length() == 1);
1963
1964 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001965 return f->IsBuiltin() ? isolate->heap()->true_value() :
1966 isolate->heap()->false_value();
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001967}
1968
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001969
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001970RUNTIME_FUNCTION(MaybeObject*, Runtime_SetCode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001971 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001972 ASSERT(args.length() == 2);
1973
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001974 CONVERT_ARG_CHECKED(JSFunction, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001975 Handle<Object> code = args.at<Object>(1);
1976
1977 Handle<Context> context(target->context());
1978
1979 if (!code->IsNull()) {
1980 RUNTIME_ASSERT(code->IsJSFunction());
1981 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001982 Handle<SharedFunctionInfo> shared(fun->shared());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001983
1984 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001985 return Failure::Exception();
1986 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001987 // Since we don't store the source for this we should never
1988 // optimize this.
1989 shared->code()->set_optimizable(false);
1990
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001991 // Set the code, scope info, formal parameter count,
1992 // and the length of the target function.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00001993 target->shared()->set_code(shared->code());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001994 target->ReplaceCode(shared->code());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001995 target->shared()->set_scope_info(shared->scope_info());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001996 target->shared()->set_length(shared->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001997 target->shared()->set_formal_parameter_count(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001998 shared->formal_parameter_count());
ager@chromium.org7c537e22008-10-16 08:43:32 +00001999 // Set the source code of the target function to undefined.
2000 // SetCode is only used for built-in constructors like String,
2001 // Array, and Object, and some web code
2002 // doesn't like seeing source code for constructors.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002003 target->shared()->set_script(isolate->heap()->undefined_value());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002004 target->shared()->code()->set_optimizable(false);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00002005 // Clear the optimization hints related to the compiled code as these are no
2006 // longer valid when the code is overwritten.
2007 target->shared()->ClearThisPropertyAssignmentsInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002008 context = Handle<Context>(fun->context());
2009
2010 // Make sure we get a fresh copy of the literal vector to avoid
2011 // cross context contamination.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002012 int number_of_literals = fun->NumberOfLiterals();
2013 Handle<FixedArray> literals =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002014 isolate->factory()->NewFixedArray(number_of_literals, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002015 if (number_of_literals > 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002016 // Insert the object, regexp and array functions in the literals
2017 // array prefix. These are the functions that will be used when
2018 // creating object, regexp and array literals.
ager@chromium.org236ad962008-09-25 09:45:57 +00002019 literals->set(JSFunction::kLiteralGlobalContextIndex,
2020 context->global_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002021 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002022 // It's okay to skip the write barrier here because the literals
2023 // are guaranteed to be in old space.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00002024 target->set_literals(*literals, SKIP_WRITE_BARRIER);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002025 target->set_next_function_link(isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002026 }
2027
2028 target->set_context(*context);
2029 return *target;
2030}
2031
2032
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002033RUNTIME_FUNCTION(MaybeObject*, Runtime_SetExpectedNumberOfProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002034 HandleScope scope(isolate);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002035 ASSERT(args.length() == 2);
2036 CONVERT_ARG_CHECKED(JSFunction, function, 0);
2037 CONVERT_SMI_CHECKED(num, args[1]);
2038 RUNTIME_ASSERT(num >= 0);
2039 SetExpectedNofProperties(function, num);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002040 return isolate->heap()->undefined_value();
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002041}
2042
2043
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002044MUST_USE_RESULT static MaybeObject* CharFromCode(Isolate* isolate,
2045 Object* char_code) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002046 uint32_t code;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002047 if (char_code->ToArrayIndex(&code)) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002048 if (code <= 0xffff) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002049 return isolate->heap()->LookupSingleCharacterStringFromCode(code);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002050 }
2051 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002052 return isolate->heap()->empty_string();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002053}
2054
2055
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002056RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCharCodeAt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002057 NoHandleAllocation ha;
2058 ASSERT(args.length() == 2);
2059
2060 CONVERT_CHECKED(String, subject, args[0]);
2061 Object* index = args[1];
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002062 RUNTIME_ASSERT(index->IsNumber());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002063
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002064 uint32_t i = 0;
2065 if (index->IsSmi()) {
2066 int value = Smi::cast(index)->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002067 if (value < 0) return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002068 i = value;
2069 } else {
2070 ASSERT(index->IsHeapNumber());
2071 double value = HeapNumber::cast(index)->value();
2072 i = static_cast<uint32_t>(DoubleToInteger(value));
kasperl@chromium.org74e4e5e2010-01-25 10:15:52 +00002073 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002074
2075 // Flatten the string. If someone wants to get a char at an index
2076 // in a cons string, it is likely that more indices will be
2077 // accessed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002078 Object* flat;
2079 { MaybeObject* maybe_flat = subject->TryFlatten();
2080 if (!maybe_flat->ToObject(&flat)) return maybe_flat;
2081 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002082 subject = String::cast(flat);
2083
2084 if (i >= static_cast<uint32_t>(subject->length())) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002085 return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002086 }
2087
2088 return Smi::FromInt(subject->Get(i));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002089}
2090
2091
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002092RUNTIME_FUNCTION(MaybeObject*, Runtime_CharFromCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002093 NoHandleAllocation ha;
2094 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002095 return CharFromCode(isolate, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002096}
2097
lrn@chromium.org25156de2010-04-06 13:10:27 +00002098
2099class FixedArrayBuilder {
2100 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002101 explicit FixedArrayBuilder(Isolate* isolate, int initial_capacity)
2102 : array_(isolate->factory()->NewFixedArrayWithHoles(initial_capacity)),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002103 length_(0) {
2104 // Require a non-zero initial size. Ensures that doubling the size to
2105 // extend the array will work.
2106 ASSERT(initial_capacity > 0);
2107 }
2108
2109 explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
2110 : array_(backing_store),
2111 length_(0) {
2112 // Require a non-zero initial size. Ensures that doubling the size to
2113 // extend the array will work.
2114 ASSERT(backing_store->length() > 0);
2115 }
2116
2117 bool HasCapacity(int elements) {
2118 int length = array_->length();
2119 int required_length = length_ + elements;
2120 return (length >= required_length);
2121 }
2122
2123 void EnsureCapacity(int elements) {
2124 int length = array_->length();
2125 int required_length = length_ + elements;
2126 if (length < required_length) {
2127 int new_length = length;
2128 do {
2129 new_length *= 2;
2130 } while (new_length < required_length);
2131 Handle<FixedArray> extended_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002132 array_->GetIsolate()->factory()->NewFixedArrayWithHoles(new_length);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002133 array_->CopyTo(0, *extended_array, 0, length_);
2134 array_ = extended_array;
2135 }
2136 }
2137
2138 void Add(Object* value) {
2139 ASSERT(length_ < capacity());
2140 array_->set(length_, value);
2141 length_++;
2142 }
2143
2144 void Add(Smi* value) {
2145 ASSERT(length_ < capacity());
2146 array_->set(length_, value);
2147 length_++;
2148 }
2149
2150 Handle<FixedArray> array() {
2151 return array_;
2152 }
2153
2154 int length() {
2155 return length_;
2156 }
2157
2158 int capacity() {
2159 return array_->length();
2160 }
2161
2162 Handle<JSArray> ToJSArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002163 Handle<JSArray> result_array = FACTORY->NewJSArrayWithElements(array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002164 result_array->set_length(Smi::FromInt(length_));
2165 return result_array;
2166 }
2167
2168 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
2169 target_array->set_elements(*array_);
2170 target_array->set_length(Smi::FromInt(length_));
2171 return target_array;
2172 }
2173
2174 private:
2175 Handle<FixedArray> array_;
2176 int length_;
2177};
2178
2179
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002180// Forward declarations.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002181const int kStringBuilderConcatHelperLengthBits = 11;
2182const int kStringBuilderConcatHelperPositionBits = 19;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002183
2184template <typename schar>
2185static inline void StringBuilderConcatHelper(String*,
2186 schar*,
2187 FixedArray*,
2188 int);
2189
lrn@chromium.org25156de2010-04-06 13:10:27 +00002190typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
2191 StringBuilderSubstringLength;
2192typedef BitField<int,
2193 kStringBuilderConcatHelperLengthBits,
2194 kStringBuilderConcatHelperPositionBits>
2195 StringBuilderSubstringPosition;
2196
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002197
2198class ReplacementStringBuilder {
2199 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002200 ReplacementStringBuilder(Heap* heap,
2201 Handle<String> subject,
2202 int estimated_part_count)
2203 : heap_(heap),
2204 array_builder_(heap->isolate(), estimated_part_count),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002205 subject_(subject),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002206 character_count_(0),
ager@chromium.org5ec48922009-05-05 07:25:34 +00002207 is_ascii_(subject->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002208 // Require a non-zero initial size. Ensures that doubling the size to
2209 // extend the array will work.
2210 ASSERT(estimated_part_count > 0);
2211 }
2212
lrn@chromium.org25156de2010-04-06 13:10:27 +00002213 static inline void AddSubjectSlice(FixedArrayBuilder* builder,
2214 int from,
2215 int to) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002216 ASSERT(from >= 0);
2217 int length = to - from;
2218 ASSERT(length > 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002219 if (StringBuilderSubstringLength::is_valid(length) &&
2220 StringBuilderSubstringPosition::is_valid(from)) {
2221 int encoded_slice = StringBuilderSubstringLength::encode(length) |
2222 StringBuilderSubstringPosition::encode(from);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002223 builder->Add(Smi::FromInt(encoded_slice));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002224 } else {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002225 // Otherwise encode as two smis.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002226 builder->Add(Smi::FromInt(-length));
2227 builder->Add(Smi::FromInt(from));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002228 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00002229 }
2230
2231
2232 void EnsureCapacity(int elements) {
2233 array_builder_.EnsureCapacity(elements);
2234 }
2235
2236
2237 void AddSubjectSlice(int from, int to) {
2238 AddSubjectSlice(&array_builder_, from, to);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002239 IncrementCharacterCount(to - from);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002240 }
2241
2242
2243 void AddString(Handle<String> string) {
2244 int length = string->length();
2245 ASSERT(length > 0);
2246 AddElement(*string);
ager@chromium.org5ec48922009-05-05 07:25:34 +00002247 if (!string->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002248 is_ascii_ = false;
2249 }
2250 IncrementCharacterCount(length);
2251 }
2252
2253
2254 Handle<String> ToString() {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002255 if (array_builder_.length() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002256 return heap_->isolate()->factory()->empty_string();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002257 }
2258
2259 Handle<String> joined_string;
2260 if (is_ascii_) {
2261 joined_string = NewRawAsciiString(character_count_);
2262 AssertNoAllocation no_alloc;
2263 SeqAsciiString* seq = SeqAsciiString::cast(*joined_string);
2264 char* char_buffer = seq->GetChars();
2265 StringBuilderConcatHelper(*subject_,
2266 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002267 *array_builder_.array(),
2268 array_builder_.length());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002269 } else {
2270 // Non-ASCII.
2271 joined_string = NewRawTwoByteString(character_count_);
2272 AssertNoAllocation no_alloc;
2273 SeqTwoByteString* seq = SeqTwoByteString::cast(*joined_string);
2274 uc16* char_buffer = seq->GetChars();
2275 StringBuilderConcatHelper(*subject_,
2276 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002277 *array_builder_.array(),
2278 array_builder_.length());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002279 }
2280 return joined_string;
2281 }
2282
2283
2284 void IncrementCharacterCount(int by) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002285 if (character_count_ > String::kMaxLength - by) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002286 V8::FatalProcessOutOfMemory("String.replace result too large.");
2287 }
2288 character_count_ += by;
2289 }
2290
lrn@chromium.org25156de2010-04-06 13:10:27 +00002291 Handle<JSArray> GetParts() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002292 return array_builder_.ToJSArray();
lrn@chromium.org25156de2010-04-06 13:10:27 +00002293 }
kmillikin@chromium.orgd9825192010-03-30 08:36:16 +00002294
lrn@chromium.org25156de2010-04-06 13:10:27 +00002295 private:
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002296 Handle<String> NewRawAsciiString(int size) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002297 CALL_HEAP_FUNCTION(heap_->isolate(),
2298 heap_->AllocateRawAsciiString(size), String);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002299 }
2300
2301
2302 Handle<String> NewRawTwoByteString(int size) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002303 CALL_HEAP_FUNCTION(heap_->isolate(),
2304 heap_->AllocateRawTwoByteString(size), String);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002305 }
2306
2307
2308 void AddElement(Object* element) {
2309 ASSERT(element->IsSmi() || element->IsString());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002310 ASSERT(array_builder_.capacity() > array_builder_.length());
2311 array_builder_.Add(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002312 }
2313
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002314 Heap* heap_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002315 FixedArrayBuilder array_builder_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002316 Handle<String> subject_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002317 int character_count_;
2318 bool is_ascii_;
2319};
2320
2321
2322class CompiledReplacement {
2323 public:
2324 CompiledReplacement()
2325 : parts_(1), replacement_substrings_(0) {}
2326
2327 void Compile(Handle<String> replacement,
2328 int capture_count,
2329 int subject_length);
2330
2331 void Apply(ReplacementStringBuilder* builder,
2332 int match_from,
2333 int match_to,
2334 Handle<JSArray> last_match_info);
2335
2336 // Number of distinct parts of the replacement pattern.
2337 int parts() {
2338 return parts_.length();
2339 }
2340 private:
2341 enum PartType {
2342 SUBJECT_PREFIX = 1,
2343 SUBJECT_SUFFIX,
2344 SUBJECT_CAPTURE,
2345 REPLACEMENT_SUBSTRING,
2346 REPLACEMENT_STRING,
2347
2348 NUMBER_OF_PART_TYPES
2349 };
2350
2351 struct ReplacementPart {
2352 static inline ReplacementPart SubjectMatch() {
2353 return ReplacementPart(SUBJECT_CAPTURE, 0);
2354 }
2355 static inline ReplacementPart SubjectCapture(int capture_index) {
2356 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
2357 }
2358 static inline ReplacementPart SubjectPrefix() {
2359 return ReplacementPart(SUBJECT_PREFIX, 0);
2360 }
2361 static inline ReplacementPart SubjectSuffix(int subject_length) {
2362 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
2363 }
2364 static inline ReplacementPart ReplacementString() {
2365 return ReplacementPart(REPLACEMENT_STRING, 0);
2366 }
2367 static inline ReplacementPart ReplacementSubString(int from, int to) {
2368 ASSERT(from >= 0);
2369 ASSERT(to > from);
2370 return ReplacementPart(-from, to);
2371 }
2372
2373 // If tag <= 0 then it is the negation of a start index of a substring of
2374 // the replacement pattern, otherwise it's a value from PartType.
2375 ReplacementPart(int tag, int data)
2376 : tag(tag), data(data) {
2377 // Must be non-positive or a PartType value.
2378 ASSERT(tag < NUMBER_OF_PART_TYPES);
2379 }
2380 // Either a value of PartType or a non-positive number that is
2381 // the negation of an index into the replacement string.
2382 int tag;
2383 // The data value's interpretation depends on the value of tag:
2384 // tag == SUBJECT_PREFIX ||
2385 // tag == SUBJECT_SUFFIX: data is unused.
2386 // tag == SUBJECT_CAPTURE: data is the number of the capture.
2387 // tag == REPLACEMENT_SUBSTRING ||
2388 // tag == REPLACEMENT_STRING: data is index into array of substrings
2389 // of the replacement string.
2390 // tag <= 0: Temporary representation of the substring of the replacement
2391 // string ranging over -tag .. data.
2392 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
2393 // substring objects.
2394 int data;
2395 };
2396
2397 template<typename Char>
2398 static void ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
2399 Vector<Char> characters,
2400 int capture_count,
2401 int subject_length) {
2402 int length = characters.length();
2403 int last = 0;
2404 for (int i = 0; i < length; i++) {
2405 Char c = characters[i];
2406 if (c == '$') {
2407 int next_index = i + 1;
2408 if (next_index == length) { // No next character!
2409 break;
2410 }
2411 Char c2 = characters[next_index];
2412 switch (c2) {
2413 case '$':
2414 if (i > last) {
2415 // There is a substring before. Include the first "$".
2416 parts->Add(ReplacementPart::ReplacementSubString(last, next_index));
2417 last = next_index + 1; // Continue after the second "$".
2418 } else {
2419 // Let the next substring start with the second "$".
2420 last = next_index;
2421 }
2422 i = next_index;
2423 break;
2424 case '`':
2425 if (i > last) {
2426 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2427 }
2428 parts->Add(ReplacementPart::SubjectPrefix());
2429 i = next_index;
2430 last = i + 1;
2431 break;
2432 case '\'':
2433 if (i > last) {
2434 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2435 }
2436 parts->Add(ReplacementPart::SubjectSuffix(subject_length));
2437 i = next_index;
2438 last = i + 1;
2439 break;
2440 case '&':
2441 if (i > last) {
2442 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2443 }
2444 parts->Add(ReplacementPart::SubjectMatch());
2445 i = next_index;
2446 last = i + 1;
2447 break;
2448 case '0':
2449 case '1':
2450 case '2':
2451 case '3':
2452 case '4':
2453 case '5':
2454 case '6':
2455 case '7':
2456 case '8':
2457 case '9': {
2458 int capture_ref = c2 - '0';
2459 if (capture_ref > capture_count) {
2460 i = next_index;
2461 continue;
2462 }
2463 int second_digit_index = next_index + 1;
2464 if (second_digit_index < length) {
2465 // Peek ahead to see if we have two digits.
2466 Char c3 = characters[second_digit_index];
2467 if ('0' <= c3 && c3 <= '9') { // Double digits.
2468 int double_digit_ref = capture_ref * 10 + c3 - '0';
2469 if (double_digit_ref <= capture_count) {
2470 next_index = second_digit_index;
2471 capture_ref = double_digit_ref;
2472 }
2473 }
2474 }
2475 if (capture_ref > 0) {
2476 if (i > last) {
2477 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2478 }
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002479 ASSERT(capture_ref <= capture_count);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002480 parts->Add(ReplacementPart::SubjectCapture(capture_ref));
2481 last = next_index + 1;
2482 }
2483 i = next_index;
2484 break;
2485 }
2486 default:
2487 i = next_index;
2488 break;
2489 }
2490 }
2491 }
2492 if (length > last) {
2493 if (last == 0) {
2494 parts->Add(ReplacementPart::ReplacementString());
2495 } else {
2496 parts->Add(ReplacementPart::ReplacementSubString(last, length));
2497 }
2498 }
2499 }
2500
2501 ZoneList<ReplacementPart> parts_;
2502 ZoneList<Handle<String> > replacement_substrings_;
2503};
2504
2505
2506void CompiledReplacement::Compile(Handle<String> replacement,
2507 int capture_count,
2508 int subject_length) {
2509 ASSERT(replacement->IsFlat());
ager@chromium.org5ec48922009-05-05 07:25:34 +00002510 if (replacement->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002511 AssertNoAllocation no_alloc;
2512 ParseReplacementPattern(&parts_,
2513 replacement->ToAsciiVector(),
2514 capture_count,
2515 subject_length);
2516 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00002517 ASSERT(replacement->IsTwoByteRepresentation());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002518 AssertNoAllocation no_alloc;
2519
2520 ParseReplacementPattern(&parts_,
2521 replacement->ToUC16Vector(),
2522 capture_count,
2523 subject_length);
2524 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002525 Isolate* isolate = replacement->GetIsolate();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002526 // Find substrings of replacement string and create them as String objects.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002527 int substring_index = 0;
2528 for (int i = 0, n = parts_.length(); i < n; i++) {
2529 int tag = parts_[i].tag;
2530 if (tag <= 0) { // A replacement string slice.
2531 int from = -tag;
2532 int to = parts_[i].data;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002533 replacement_substrings_.Add(
2534 isolate->factory()->NewSubString(replacement, from, to));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002535 parts_[i].tag = REPLACEMENT_SUBSTRING;
2536 parts_[i].data = substring_index;
2537 substring_index++;
2538 } else if (tag == REPLACEMENT_STRING) {
2539 replacement_substrings_.Add(replacement);
2540 parts_[i].data = substring_index;
2541 substring_index++;
2542 }
2543 }
2544}
2545
2546
2547void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
2548 int match_from,
2549 int match_to,
2550 Handle<JSArray> last_match_info) {
2551 for (int i = 0, n = parts_.length(); i < n; i++) {
2552 ReplacementPart part = parts_[i];
2553 switch (part.tag) {
2554 case SUBJECT_PREFIX:
2555 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
2556 break;
2557 case SUBJECT_SUFFIX: {
2558 int subject_length = part.data;
2559 if (match_to < subject_length) {
2560 builder->AddSubjectSlice(match_to, subject_length);
2561 }
2562 break;
2563 }
2564 case SUBJECT_CAPTURE: {
2565 int capture = part.data;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002566 FixedArray* match_info = FixedArray::cast(last_match_info->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002567 int from = RegExpImpl::GetCapture(match_info, capture * 2);
2568 int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1);
2569 if (from >= 0 && to > from) {
2570 builder->AddSubjectSlice(from, to);
2571 }
2572 break;
2573 }
2574 case REPLACEMENT_SUBSTRING:
2575 case REPLACEMENT_STRING:
2576 builder->AddString(replacement_substrings_[part.data]);
2577 break;
2578 default:
2579 UNREACHABLE();
2580 }
2581 }
2582}
2583
2584
2585
lrn@chromium.org303ada72010-10-27 09:33:13 +00002586MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002587 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002588 String* subject,
2589 JSRegExp* regexp,
2590 String* replacement,
2591 JSArray* last_match_info) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002592 ASSERT(subject->IsFlat());
2593 ASSERT(replacement->IsFlat());
2594
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002595 HandleScope handles(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002596
2597 int length = subject->length();
2598 Handle<String> subject_handle(subject);
2599 Handle<JSRegExp> regexp_handle(regexp);
2600 Handle<String> replacement_handle(replacement);
2601 Handle<JSArray> last_match_info_handle(last_match_info);
2602 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2603 subject_handle,
2604 0,
2605 last_match_info_handle);
2606 if (match.is_null()) {
2607 return Failure::Exception();
2608 }
2609 if (match->IsNull()) {
2610 return *subject_handle;
2611 }
2612
2613 int capture_count = regexp_handle->CaptureCount();
2614
2615 // CompiledReplacement uses zone allocation.
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00002616 CompilationZoneScope zone(DELETE_ON_EXIT);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002617 CompiledReplacement compiled_replacement;
2618 compiled_replacement.Compile(replacement_handle,
2619 capture_count,
2620 length);
2621
2622 bool is_global = regexp_handle->GetFlags().is_global();
2623
2624 // Guessing the number of parts that the final result string is built
2625 // from. Global regexps can match any number of times, so we guess
2626 // conservatively.
2627 int expected_parts =
2628 (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002629 ReplacementStringBuilder builder(isolate->heap(),
2630 subject_handle,
2631 expected_parts);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002632
2633 // Index of end of last match.
2634 int prev = 0;
2635
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002636 // Number of parts added by compiled replacement plus preceeding
2637 // string and possibly suffix after last match. It is possible for
2638 // all components to use two elements when encoded as two smis.
2639 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002640 bool matched = true;
2641 do {
2642 ASSERT(last_match_info_handle->HasFastElements());
2643 // Increase the capacity of the builder before entering local handle-scope,
2644 // so its internal buffer can safely allocate a new handle if it grows.
2645 builder.EnsureCapacity(parts_added_per_loop);
2646
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002647 HandleScope loop_scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002648 int start, end;
2649 {
2650 AssertNoAllocation match_info_array_is_not_in_a_handle;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002651 FixedArray* match_info_array =
2652 FixedArray::cast(last_match_info_handle->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002653
2654 ASSERT_EQ(capture_count * 2 + 2,
2655 RegExpImpl::GetLastCaptureCount(match_info_array));
2656 start = RegExpImpl::GetCapture(match_info_array, 0);
2657 end = RegExpImpl::GetCapture(match_info_array, 1);
2658 }
2659
2660 if (prev < start) {
2661 builder.AddSubjectSlice(prev, start);
2662 }
2663 compiled_replacement.Apply(&builder,
2664 start,
2665 end,
2666 last_match_info_handle);
2667 prev = end;
2668
2669 // Only continue checking for global regexps.
2670 if (!is_global) break;
2671
2672 // Continue from where the match ended, unless it was an empty match.
2673 int next = end;
2674 if (start == end) {
2675 next = end + 1;
2676 if (next > length) break;
2677 }
2678
2679 match = RegExpImpl::Exec(regexp_handle,
2680 subject_handle,
2681 next,
2682 last_match_info_handle);
2683 if (match.is_null()) {
2684 return Failure::Exception();
2685 }
2686 matched = !match->IsNull();
2687 } while (matched);
2688
2689 if (prev < length) {
2690 builder.AddSubjectSlice(prev, length);
2691 }
2692
2693 return *(builder.ToString());
2694}
2695
2696
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002697template <typename ResultSeqString>
lrn@chromium.org303ada72010-10-27 09:33:13 +00002698MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002699 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002700 String* subject,
2701 JSRegExp* regexp,
2702 JSArray* last_match_info) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002703 ASSERT(subject->IsFlat());
2704
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002705 HandleScope handles(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002706
2707 Handle<String> subject_handle(subject);
2708 Handle<JSRegExp> regexp_handle(regexp);
2709 Handle<JSArray> last_match_info_handle(last_match_info);
2710 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2711 subject_handle,
2712 0,
2713 last_match_info_handle);
2714 if (match.is_null()) return Failure::Exception();
2715 if (match->IsNull()) return *subject_handle;
2716
2717 ASSERT(last_match_info_handle->HasFastElements());
2718
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002719 int start, end;
2720 {
2721 AssertNoAllocation match_info_array_is_not_in_a_handle;
2722 FixedArray* match_info_array =
2723 FixedArray::cast(last_match_info_handle->elements());
2724
2725 start = RegExpImpl::GetCapture(match_info_array, 0);
2726 end = RegExpImpl::GetCapture(match_info_array, 1);
2727 }
2728
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00002729 int length = subject_handle->length();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002730 int new_length = length - (end - start);
2731 if (new_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002732 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002733 }
2734 Handle<ResultSeqString> answer;
2735 if (ResultSeqString::kHasAsciiEncoding) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002736 answer = Handle<ResultSeqString>::cast(
2737 isolate->factory()->NewRawAsciiString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002738 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002739 answer = Handle<ResultSeqString>::cast(
2740 isolate->factory()->NewRawTwoByteString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002741 }
2742
2743 // If the regexp isn't global, only match once.
2744 if (!regexp_handle->GetFlags().is_global()) {
2745 if (start > 0) {
2746 String::WriteToFlat(*subject_handle,
2747 answer->GetChars(),
2748 0,
2749 start);
2750 }
2751 if (end < length) {
2752 String::WriteToFlat(*subject_handle,
2753 answer->GetChars() + start,
2754 end,
2755 length);
2756 }
2757 return *answer;
2758 }
2759
2760 int prev = 0; // Index of end of last match.
2761 int next = 0; // Start of next search (prev unless last match was empty).
2762 int position = 0;
2763
2764 do {
2765 if (prev < start) {
2766 // Add substring subject[prev;start] to answer string.
2767 String::WriteToFlat(*subject_handle,
2768 answer->GetChars() + position,
2769 prev,
2770 start);
2771 position += start - prev;
2772 }
2773 prev = end;
2774 next = end;
2775 // Continue from where the match ended, unless it was an empty match.
2776 if (start == end) {
2777 next++;
2778 if (next > length) break;
2779 }
2780 match = RegExpImpl::Exec(regexp_handle,
2781 subject_handle,
2782 next,
2783 last_match_info_handle);
2784 if (match.is_null()) return Failure::Exception();
2785 if (match->IsNull()) break;
2786
2787 ASSERT(last_match_info_handle->HasFastElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002788 HandleScope loop_scope(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002789 {
2790 AssertNoAllocation match_info_array_is_not_in_a_handle;
2791 FixedArray* match_info_array =
2792 FixedArray::cast(last_match_info_handle->elements());
2793 start = RegExpImpl::GetCapture(match_info_array, 0);
2794 end = RegExpImpl::GetCapture(match_info_array, 1);
2795 }
2796 } while (true);
2797
2798 if (prev < length) {
2799 // Add substring subject[prev;length] to answer string.
2800 String::WriteToFlat(*subject_handle,
2801 answer->GetChars() + position,
2802 prev,
2803 length);
2804 position += length - prev;
2805 }
2806
2807 if (position == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002808 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002809 }
2810
2811 // Shorten string and fill
2812 int string_size = ResultSeqString::SizeFor(position);
2813 int allocated_string_size = ResultSeqString::SizeFor(new_length);
2814 int delta = allocated_string_size - string_size;
2815
2816 answer->set_length(position);
2817 if (delta == 0) return *answer;
2818
2819 Address end_of_string = answer->address() + string_size;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002820 isolate->heap()->CreateFillerObjectAt(end_of_string, delta);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002821
2822 return *answer;
2823}
2824
2825
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002826RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceRegExpWithString) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002827 ASSERT(args.length() == 4);
2828
2829 CONVERT_CHECKED(String, subject, args[0]);
2830 if (!subject->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002831 Object* flat_subject;
2832 { MaybeObject* maybe_flat_subject = subject->TryFlatten();
2833 if (!maybe_flat_subject->ToObject(&flat_subject)) {
2834 return maybe_flat_subject;
2835 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002836 }
2837 subject = String::cast(flat_subject);
2838 }
2839
2840 CONVERT_CHECKED(String, replacement, args[2]);
2841 if (!replacement->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002842 Object* flat_replacement;
2843 { MaybeObject* maybe_flat_replacement = replacement->TryFlatten();
2844 if (!maybe_flat_replacement->ToObject(&flat_replacement)) {
2845 return maybe_flat_replacement;
2846 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002847 }
2848 replacement = String::cast(flat_replacement);
2849 }
2850
2851 CONVERT_CHECKED(JSRegExp, regexp, args[1]);
2852 CONVERT_CHECKED(JSArray, last_match_info, args[3]);
2853
2854 ASSERT(last_match_info->HasFastElements());
2855
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002856 if (replacement->length() == 0) {
2857 if (subject->HasOnlyAsciiChars()) {
2858 return StringReplaceRegExpWithEmptyString<SeqAsciiString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002859 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002860 } else {
2861 return StringReplaceRegExpWithEmptyString<SeqTwoByteString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002862 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002863 }
2864 }
2865
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002866 return StringReplaceRegExpWithString(isolate,
2867 subject,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002868 regexp,
2869 replacement,
2870 last_match_info);
2871}
2872
2873
ager@chromium.org7c537e22008-10-16 08:43:32 +00002874// Perform string match of pattern on subject, starting at start index.
2875// Caller must ensure that 0 <= start_index <= sub->length(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002876// and should check that pat->length() + start_index <= sub->length().
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002877int Runtime::StringMatch(Isolate* isolate,
2878 Handle<String> sub,
ager@chromium.org7c537e22008-10-16 08:43:32 +00002879 Handle<String> pat,
2880 int start_index) {
2881 ASSERT(0 <= start_index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002882 ASSERT(start_index <= sub->length());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002883
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00002884 int pattern_length = pat->length();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002885 if (pattern_length == 0) return start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002886
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002887 int subject_length = sub->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00002888 if (start_index + pattern_length > subject_length) return -1;
2889
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002890 if (!sub->IsFlat()) FlattenString(sub);
2891 if (!pat->IsFlat()) FlattenString(pat);
ager@chromium.org236ad962008-09-25 09:45:57 +00002892
ager@chromium.org7c537e22008-10-16 08:43:32 +00002893 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002894 // Extract flattened substrings of cons strings before determining asciiness.
2895 String* seq_sub = *sub;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002896 if (seq_sub->IsConsString()) seq_sub = ConsString::cast(seq_sub)->first();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002897 String* seq_pat = *pat;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002898 if (seq_pat->IsConsString()) seq_pat = ConsString::cast(seq_pat)->first();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002899
ager@chromium.org7c537e22008-10-16 08:43:32 +00002900 // dispatch on type of strings
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002901 if (seq_pat->IsAsciiRepresentation()) {
2902 Vector<const char> pat_vector = seq_pat->ToAsciiVector();
2903 if (seq_sub->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002904 return SearchString(isolate,
2905 seq_sub->ToAsciiVector(),
2906 pat_vector,
2907 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00002908 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002909 return SearchString(isolate,
2910 seq_sub->ToUC16Vector(),
2911 pat_vector,
2912 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00002913 }
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002914 Vector<const uc16> pat_vector = seq_pat->ToUC16Vector();
2915 if (seq_sub->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002916 return SearchString(isolate,
2917 seq_sub->ToAsciiVector(),
2918 pat_vector,
2919 start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002920 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002921 return SearchString(isolate,
2922 seq_sub->ToUC16Vector(),
2923 pat_vector,
2924 start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002925}
2926
2927
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002928RUNTIME_FUNCTION(MaybeObject*, Runtime_StringIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002929 HandleScope scope(isolate); // create a new handle scope
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002930 ASSERT(args.length() == 3);
2931
ager@chromium.org7c537e22008-10-16 08:43:32 +00002932 CONVERT_ARG_CHECKED(String, sub, 0);
2933 CONVERT_ARG_CHECKED(String, pat, 1);
2934
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002935 Object* index = args[2];
2936 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002937 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002938
ager@chromium.org870a0b62008-11-04 11:43:05 +00002939 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002940 int position =
2941 Runtime::StringMatch(isolate, sub, pat, start_index);
ager@chromium.org7c537e22008-10-16 08:43:32 +00002942 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002943}
2944
2945
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002946template <typename schar, typename pchar>
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002947static int StringMatchBackwards(Vector<const schar> subject,
2948 Vector<const pchar> pattern,
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002949 int idx) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002950 int pattern_length = pattern.length();
2951 ASSERT(pattern_length >= 1);
2952 ASSERT(idx + pattern_length <= subject.length());
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002953
2954 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002955 for (int i = 0; i < pattern_length; i++) {
2956 uc16 c = pattern[i];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002957 if (c > String::kMaxAsciiCharCode) {
2958 return -1;
2959 }
2960 }
2961 }
2962
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002963 pchar pattern_first_char = pattern[0];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002964 for (int i = idx; i >= 0; i--) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002965 if (subject[i] != pattern_first_char) continue;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002966 int j = 1;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002967 while (j < pattern_length) {
2968 if (pattern[j] != subject[i+j]) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002969 break;
2970 }
2971 j++;
2972 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002973 if (j == pattern_length) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002974 return i;
2975 }
2976 }
2977 return -1;
2978}
2979
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002980RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLastIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002981 HandleScope scope(isolate); // create a new handle scope
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002982 ASSERT(args.length() == 3);
2983
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002984 CONVERT_ARG_CHECKED(String, sub, 0);
2985 CONVERT_ARG_CHECKED(String, pat, 1);
2986
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002987 Object* index = args[2];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002988 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002989 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002990
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002991 uint32_t pat_length = pat->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002992 uint32_t sub_length = sub->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002993
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002994 if (start_index + pat_length > sub_length) {
2995 start_index = sub_length - pat_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +00002996 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002997
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002998 if (pat_length == 0) {
2999 return Smi::FromInt(start_index);
3000 }
3001
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003002 if (!sub->IsFlat()) FlattenString(sub);
3003 if (!pat->IsFlat()) FlattenString(pat);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003004
3005 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
3006
3007 int position = -1;
3008
3009 if (pat->IsAsciiRepresentation()) {
3010 Vector<const char> pat_vector = pat->ToAsciiVector();
3011 if (sub->IsAsciiRepresentation()) {
3012 position = StringMatchBackwards(sub->ToAsciiVector(),
3013 pat_vector,
3014 start_index);
3015 } else {
3016 position = StringMatchBackwards(sub->ToUC16Vector(),
3017 pat_vector,
3018 start_index);
3019 }
3020 } else {
3021 Vector<const uc16> pat_vector = pat->ToUC16Vector();
3022 if (sub->IsAsciiRepresentation()) {
3023 position = StringMatchBackwards(sub->ToAsciiVector(),
3024 pat_vector,
3025 start_index);
3026 } else {
3027 position = StringMatchBackwards(sub->ToUC16Vector(),
3028 pat_vector,
3029 start_index);
3030 }
3031 }
3032
3033 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003034}
3035
3036
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003037RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLocaleCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003038 NoHandleAllocation ha;
3039 ASSERT(args.length() == 2);
3040
3041 CONVERT_CHECKED(String, str1, args[0]);
3042 CONVERT_CHECKED(String, str2, args[1]);
3043
3044 if (str1 == str2) return Smi::FromInt(0); // Equal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003045 int str1_length = str1->length();
3046 int str2_length = str2->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003047
3048 // Decide trivial cases without flattening.
3049 if (str1_length == 0) {
3050 if (str2_length == 0) return Smi::FromInt(0); // Equal.
3051 return Smi::FromInt(-str2_length);
3052 } else {
3053 if (str2_length == 0) return Smi::FromInt(str1_length);
3054 }
3055
3056 int end = str1_length < str2_length ? str1_length : str2_length;
3057
3058 // No need to flatten if we are going to find the answer on the first
3059 // character. At this point we know there is at least one character
3060 // in each string, due to the trivial case handling above.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003061 int d = str1->Get(0) - str2->Get(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003062 if (d != 0) return Smi::FromInt(d);
3063
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003064 str1->TryFlatten();
3065 str2->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003066
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003067 StringInputBuffer& buf1 =
3068 *isolate->runtime_state()->string_locale_compare_buf1();
3069 StringInputBuffer& buf2 =
3070 *isolate->runtime_state()->string_locale_compare_buf2();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003071
3072 buf1.Reset(str1);
3073 buf2.Reset(str2);
3074
3075 for (int i = 0; i < end; i++) {
3076 uint16_t char1 = buf1.GetNext();
3077 uint16_t char2 = buf2.GetNext();
3078 if (char1 != char2) return Smi::FromInt(char1 - char2);
3079 }
3080
3081 return Smi::FromInt(str1_length - str2_length);
3082}
3083
3084
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003085RUNTIME_FUNCTION(MaybeObject*, Runtime_SubString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003086 NoHandleAllocation ha;
3087 ASSERT(args.length() == 3);
3088
3089 CONVERT_CHECKED(String, value, args[0]);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003090 Object* from = args[1];
3091 Object* to = args[2];
3092 int start, end;
3093 // We have a fast integer-only case here to avoid a conversion to double in
3094 // the common case where from and to are Smis.
3095 if (from->IsSmi() && to->IsSmi()) {
3096 start = Smi::cast(from)->value();
3097 end = Smi::cast(to)->value();
3098 } else {
3099 CONVERT_DOUBLE_CHECKED(from_number, from);
3100 CONVERT_DOUBLE_CHECKED(to_number, to);
3101 start = FastD2I(from_number);
3102 end = FastD2I(to_number);
3103 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003104 RUNTIME_ASSERT(end >= start);
3105 RUNTIME_ASSERT(start >= 0);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003106 RUNTIME_ASSERT(end <= value->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003107 isolate->counters()->sub_string_runtime()->Increment();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003108 return value->SubString(start, end);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003109}
3110
3111
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003112RUNTIME_FUNCTION(MaybeObject*, Runtime_StringMatch) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003113 ASSERT_EQ(3, args.length());
3114
3115 CONVERT_ARG_CHECKED(String, subject, 0);
3116 CONVERT_ARG_CHECKED(JSRegExp, regexp, 1);
3117 CONVERT_ARG_CHECKED(JSArray, regexp_info, 2);
3118 HandleScope handles;
3119
3120 Handle<Object> match = RegExpImpl::Exec(regexp, subject, 0, regexp_info);
3121
3122 if (match.is_null()) {
3123 return Failure::Exception();
3124 }
3125 if (match->IsNull()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003126 return isolate->heap()->null_value();
ager@chromium.org41826e72009-03-30 13:30:57 +00003127 }
3128 int length = subject->length();
3129
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00003130 CompilationZoneScope zone_space(DELETE_ON_EXIT);
ager@chromium.org41826e72009-03-30 13:30:57 +00003131 ZoneList<int> offsets(8);
3132 do {
3133 int start;
3134 int end;
3135 {
3136 AssertNoAllocation no_alloc;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003137 FixedArray* elements = FixedArray::cast(regexp_info->elements());
ager@chromium.org41826e72009-03-30 13:30:57 +00003138 start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value();
3139 end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value();
3140 }
3141 offsets.Add(start);
3142 offsets.Add(end);
3143 int index = start < end ? end : end + 1;
3144 if (index > length) break;
3145 match = RegExpImpl::Exec(regexp, subject, index, regexp_info);
3146 if (match.is_null()) {
3147 return Failure::Exception();
3148 }
3149 } while (!match->IsNull());
3150 int matches = offsets.length() / 2;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003151 Handle<FixedArray> elements = isolate->factory()->NewFixedArray(matches);
ager@chromium.org41826e72009-03-30 13:30:57 +00003152 for (int i = 0; i < matches ; i++) {
3153 int from = offsets.at(i * 2);
3154 int to = offsets.at(i * 2 + 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003155 Handle<String> match = isolate->factory()->NewSubString(subject, from, to);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003156 elements->set(i, *match);
ager@chromium.org41826e72009-03-30 13:30:57 +00003157 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003158 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.org41826e72009-03-30 13:30:57 +00003159 result->set_length(Smi::FromInt(matches));
3160 return *result;
3161}
3162
3163
lrn@chromium.org25156de2010-04-06 13:10:27 +00003164// Two smis before and after the match, for very long strings.
3165const int kMaxBuilderEntriesPerRegExpMatch = 5;
3166
3167
3168static void SetLastMatchInfoNoCaptures(Handle<String> subject,
3169 Handle<JSArray> last_match_info,
3170 int match_start,
3171 int match_end) {
3172 // Fill last_match_info with a single capture.
3173 last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead);
3174 AssertNoAllocation no_gc;
3175 FixedArray* elements = FixedArray::cast(last_match_info->elements());
3176 RegExpImpl::SetLastCaptureCount(elements, 2);
3177 RegExpImpl::SetLastInput(elements, *subject);
3178 RegExpImpl::SetLastSubject(elements, *subject);
3179 RegExpImpl::SetCapture(elements, 0, match_start);
3180 RegExpImpl::SetCapture(elements, 1, match_end);
3181}
3182
3183
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003184template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003185static bool SearchStringMultiple(Isolate* isolate,
3186 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003187 Vector<const PatternChar> pattern,
3188 String* pattern_string,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003189 FixedArrayBuilder* builder,
3190 int* match_pos) {
3191 int pos = *match_pos;
3192 int subject_length = subject.length();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003193 int pattern_length = pattern.length();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003194 int max_search_start = subject_length - pattern_length;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003195 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003196 while (pos <= max_search_start) {
3197 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
3198 *match_pos = pos;
3199 return false;
3200 }
3201 // Position of end of previous match.
3202 int match_end = pos + pattern_length;
3203 int new_pos = search.Search(subject, match_end);
3204 if (new_pos >= 0) {
3205 // A match.
3206 if (new_pos > match_end) {
3207 ReplacementStringBuilder::AddSubjectSlice(builder,
3208 match_end,
3209 new_pos);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003210 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003211 pos = new_pos;
3212 builder->Add(pattern_string);
3213 } else {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003214 break;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003215 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003216 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003217
lrn@chromium.org25156de2010-04-06 13:10:27 +00003218 if (pos < max_search_start) {
3219 ReplacementStringBuilder::AddSubjectSlice(builder,
3220 pos + pattern_length,
3221 subject_length);
3222 }
3223 *match_pos = pos;
3224 return true;
3225}
3226
3227
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003228static bool SearchStringMultiple(Isolate* isolate,
3229 Handle<String> subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003230 Handle<String> pattern,
3231 Handle<JSArray> last_match_info,
3232 FixedArrayBuilder* builder) {
3233 ASSERT(subject->IsFlat());
3234 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003235
3236 // Treating as if a previous match was before first character.
3237 int match_pos = -pattern->length();
3238
3239 for (;;) { // Break when search complete.
3240 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3241 AssertNoAllocation no_gc;
3242 if (subject->IsAsciiRepresentation()) {
3243 Vector<const char> subject_vector = subject->ToAsciiVector();
3244 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003245 if (SearchStringMultiple(isolate,
3246 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003247 pattern->ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003248 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003249 builder,
3250 &match_pos)) break;
3251 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003252 if (SearchStringMultiple(isolate,
3253 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003254 pattern->ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003255 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003256 builder,
3257 &match_pos)) break;
3258 }
3259 } else {
3260 Vector<const uc16> subject_vector = subject->ToUC16Vector();
3261 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003262 if (SearchStringMultiple(isolate,
3263 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003264 pattern->ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003265 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003266 builder,
3267 &match_pos)) break;
3268 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003269 if (SearchStringMultiple(isolate,
3270 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003271 pattern->ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003272 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003273 builder,
3274 &match_pos)) break;
3275 }
3276 }
3277 }
3278
3279 if (match_pos >= 0) {
3280 SetLastMatchInfoNoCaptures(subject,
3281 last_match_info,
3282 match_pos,
3283 match_pos + pattern->length());
3284 return true;
3285 }
3286 return false; // No matches at all.
3287}
3288
3289
3290static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003291 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003292 Handle<String> subject,
3293 Handle<JSRegExp> regexp,
3294 Handle<JSArray> last_match_array,
3295 FixedArrayBuilder* builder) {
3296 ASSERT(subject->IsFlat());
3297 int match_start = -1;
3298 int match_end = 0;
3299 int pos = 0;
3300 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3301 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3302
3303 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003304 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003305 int subject_length = subject->length();
3306
3307 for (;;) { // Break on failure, return on exception.
3308 RegExpImpl::IrregexpResult result =
3309 RegExpImpl::IrregexpExecOnce(regexp,
3310 subject,
3311 pos,
3312 register_vector);
3313 if (result == RegExpImpl::RE_SUCCESS) {
3314 match_start = register_vector[0];
3315 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3316 if (match_end < match_start) {
3317 ReplacementStringBuilder::AddSubjectSlice(builder,
3318 match_end,
3319 match_start);
3320 }
3321 match_end = register_vector[1];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003322 HandleScope loop_scope(isolate);
3323 builder->Add(*isolate->factory()->NewSubString(subject,
3324 match_start,
3325 match_end));
lrn@chromium.org25156de2010-04-06 13:10:27 +00003326 if (match_start != match_end) {
3327 pos = match_end;
3328 } else {
3329 pos = match_end + 1;
3330 if (pos > subject_length) break;
3331 }
3332 } else if (result == RegExpImpl::RE_FAILURE) {
3333 break;
3334 } else {
3335 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3336 return result;
3337 }
3338 }
3339
3340 if (match_start >= 0) {
3341 if (match_end < subject_length) {
3342 ReplacementStringBuilder::AddSubjectSlice(builder,
3343 match_end,
3344 subject_length);
3345 }
3346 SetLastMatchInfoNoCaptures(subject,
3347 last_match_array,
3348 match_start,
3349 match_end);
3350 return RegExpImpl::RE_SUCCESS;
3351 } else {
3352 return RegExpImpl::RE_FAILURE; // No matches at all.
3353 }
3354}
3355
3356
3357static RegExpImpl::IrregexpResult SearchRegExpMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003358 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003359 Handle<String> subject,
3360 Handle<JSRegExp> regexp,
3361 Handle<JSArray> last_match_array,
3362 FixedArrayBuilder* builder) {
3363
3364 ASSERT(subject->IsFlat());
3365 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3366 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3367
3368 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003369 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003370
3371 RegExpImpl::IrregexpResult result =
3372 RegExpImpl::IrregexpExecOnce(regexp,
3373 subject,
3374 0,
3375 register_vector);
3376
3377 int capture_count = regexp->CaptureCount();
3378 int subject_length = subject->length();
3379
3380 // Position to search from.
3381 int pos = 0;
3382 // End of previous match. Differs from pos if match was empty.
3383 int match_end = 0;
3384 if (result == RegExpImpl::RE_SUCCESS) {
3385 // Need to keep a copy of the previous match for creating last_match_info
3386 // at the end, so we have two vectors that we swap between.
3387 OffsetsVector registers2(required_registers);
3388 Vector<int> prev_register_vector(registers2.vector(), registers2.length());
3389
3390 do {
3391 int match_start = register_vector[0];
3392 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3393 if (match_end < match_start) {
3394 ReplacementStringBuilder::AddSubjectSlice(builder,
3395 match_end,
3396 match_start);
3397 }
3398 match_end = register_vector[1];
3399
3400 {
3401 // Avoid accumulating new handles inside loop.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003402 HandleScope temp_scope(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003403 // Arguments array to replace function is match, captures, index and
3404 // subject, i.e., 3 + capture count in total.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003405 Handle<FixedArray> elements =
3406 isolate->factory()->NewFixedArray(3 + capture_count);
3407 Handle<String> match = isolate->factory()->NewSubString(subject,
3408 match_start,
3409 match_end);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003410 elements->set(0, *match);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003411 for (int i = 1; i <= capture_count; i++) {
3412 int start = register_vector[i * 2];
3413 if (start >= 0) {
3414 int end = register_vector[i * 2 + 1];
3415 ASSERT(start <= end);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003416 Handle<String> substring = isolate->factory()->NewSubString(subject,
3417 start,
3418 end);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003419 elements->set(i, *substring);
3420 } else {
3421 ASSERT(register_vector[i * 2 + 1] < 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003422 elements->set(i, isolate->heap()->undefined_value());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003423 }
3424 }
3425 elements->set(capture_count + 1, Smi::FromInt(match_start));
3426 elements->set(capture_count + 2, *subject);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003427 builder->Add(*isolate->factory()->NewJSArrayWithElements(elements));
lrn@chromium.org25156de2010-04-06 13:10:27 +00003428 }
3429 // Swap register vectors, so the last successful match is in
3430 // prev_register_vector.
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003431 Vector<int32_t> tmp = prev_register_vector;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003432 prev_register_vector = register_vector;
3433 register_vector = tmp;
3434
3435 if (match_end > match_start) {
3436 pos = match_end;
3437 } else {
3438 pos = match_end + 1;
3439 if (pos > subject_length) {
3440 break;
3441 }
3442 }
3443
3444 result = RegExpImpl::IrregexpExecOnce(regexp,
3445 subject,
3446 pos,
3447 register_vector);
3448 } while (result == RegExpImpl::RE_SUCCESS);
3449
3450 if (result != RegExpImpl::RE_EXCEPTION) {
3451 // Finished matching, with at least one match.
3452 if (match_end < subject_length) {
3453 ReplacementStringBuilder::AddSubjectSlice(builder,
3454 match_end,
3455 subject_length);
3456 }
3457
3458 int last_match_capture_count = (capture_count + 1) * 2;
3459 int last_match_array_size =
3460 last_match_capture_count + RegExpImpl::kLastMatchOverhead;
3461 last_match_array->EnsureSize(last_match_array_size);
3462 AssertNoAllocation no_gc;
3463 FixedArray* elements = FixedArray::cast(last_match_array->elements());
3464 RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count);
3465 RegExpImpl::SetLastSubject(elements, *subject);
3466 RegExpImpl::SetLastInput(elements, *subject);
3467 for (int i = 0; i < last_match_capture_count; i++) {
3468 RegExpImpl::SetCapture(elements, i, prev_register_vector[i]);
3469 }
3470 return RegExpImpl::RE_SUCCESS;
3471 }
3472 }
3473 // No matches at all, return failure or exception result directly.
3474 return result;
3475}
3476
3477
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003478RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExecMultiple) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003479 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003480 HandleScope handles(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003481
3482 CONVERT_ARG_CHECKED(String, subject, 1);
3483 if (!subject->IsFlat()) { FlattenString(subject); }
3484 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
3485 CONVERT_ARG_CHECKED(JSArray, last_match_info, 2);
3486 CONVERT_ARG_CHECKED(JSArray, result_array, 3);
3487
3488 ASSERT(last_match_info->HasFastElements());
3489 ASSERT(regexp->GetFlags().is_global());
3490 Handle<FixedArray> result_elements;
3491 if (result_array->HasFastElements()) {
3492 result_elements =
3493 Handle<FixedArray>(FixedArray::cast(result_array->elements()));
3494 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003495 result_elements = isolate->factory()->NewFixedArrayWithHoles(16);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003496 }
3497 FixedArrayBuilder builder(result_elements);
3498
3499 if (regexp->TypeTag() == JSRegExp::ATOM) {
3500 Handle<String> pattern(
3501 String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003502 ASSERT(pattern->IsFlat());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003503 if (SearchStringMultiple(isolate, subject, pattern,
3504 last_match_info, &builder)) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003505 return *builder.ToJSArray(result_array);
3506 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003507 return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003508 }
3509
3510 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
3511
3512 RegExpImpl::IrregexpResult result;
3513 if (regexp->CaptureCount() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003514 result = SearchRegExpNoCaptureMultiple(isolate,
3515 subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003516 regexp,
3517 last_match_info,
3518 &builder);
3519 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003520 result = SearchRegExpMultiple(isolate,
3521 subject,
3522 regexp,
3523 last_match_info,
3524 &builder);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003525 }
3526 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003527 if (result == RegExpImpl::RE_FAILURE) return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003528 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3529 return Failure::Exception();
3530}
3531
3532
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003533RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToRadixString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003534 NoHandleAllocation ha;
3535 ASSERT(args.length() == 2);
3536
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003537 // Fast case where the result is a one character string.
3538 if (args[0]->IsSmi() && args[1]->IsSmi()) {
3539 int value = Smi::cast(args[0])->value();
3540 int radix = Smi::cast(args[1])->value();
3541 if (value >= 0 && value < radix) {
3542 RUNTIME_ASSERT(radix <= 36);
3543 // Character array used for conversion.
3544 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003545 return isolate->heap()->
3546 LookupSingleCharacterStringFromCode(kCharTable[value]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003547 }
3548 }
3549
3550 // Slow case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003551 CONVERT_DOUBLE_CHECKED(value, args[0]);
3552 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003553 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003554 }
3555 if (isinf(value)) {
3556 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003557 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003558 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003559 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003560 }
3561 CONVERT_DOUBLE_CHECKED(radix_number, args[1]);
3562 int radix = FastD2I(radix_number);
3563 RUNTIME_ASSERT(2 <= radix && radix <= 36);
3564 char* str = DoubleToRadixCString(value, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003565 MaybeObject* result =
3566 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003567 DeleteArray(str);
3568 return result;
3569}
3570
3571
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003572RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToFixed) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003573 NoHandleAllocation ha;
3574 ASSERT(args.length() == 2);
3575
3576 CONVERT_DOUBLE_CHECKED(value, args[0]);
3577 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003578 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003579 }
3580 if (isinf(value)) {
3581 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003582 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003583 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003584 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003585 }
3586 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3587 int f = FastD2I(f_number);
3588 RUNTIME_ASSERT(f >= 0);
3589 char* str = DoubleToFixedCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003590 MaybeObject* res =
3591 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003592 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003593 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003594}
3595
3596
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003597RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToExponential) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003598 NoHandleAllocation ha;
3599 ASSERT(args.length() == 2);
3600
3601 CONVERT_DOUBLE_CHECKED(value, args[0]);
3602 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003603 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003604 }
3605 if (isinf(value)) {
3606 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003607 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003608 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003609 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003610 }
3611 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3612 int f = FastD2I(f_number);
3613 RUNTIME_ASSERT(f >= -1 && f <= 20);
3614 char* str = DoubleToExponentialCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003615 MaybeObject* res =
3616 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003617 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003618 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003619}
3620
3621
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003622RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToPrecision) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003623 NoHandleAllocation ha;
3624 ASSERT(args.length() == 2);
3625
3626 CONVERT_DOUBLE_CHECKED(value, args[0]);
3627 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003628 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003629 }
3630 if (isinf(value)) {
3631 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003632 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003633 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003634 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003635 }
3636 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3637 int f = FastD2I(f_number);
3638 RUNTIME_ASSERT(f >= 1 && f <= 21);
3639 char* str = DoubleToPrecisionCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003640 MaybeObject* res =
3641 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003642 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003643 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003644}
3645
3646
3647// Returns a single character string where first character equals
3648// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003649static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003650 if (index < static_cast<uint32_t>(string->length())) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003651 string->TryFlatten();
ager@chromium.org870a0b62008-11-04 11:43:05 +00003652 return LookupSingleCharacterStringFromCode(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003653 string->Get(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003654 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003655 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003656}
3657
3658
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003659MaybeObject* Runtime::GetElementOrCharAt(Isolate* isolate,
3660 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003661 uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003662 // Handle [] indexing on Strings
3663 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003664 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
3665 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003666 }
3667
3668 // Handle [] indexing on String objects
3669 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003670 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
3671 Handle<Object> result =
3672 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
3673 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003674 }
3675
3676 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003677 Handle<Object> prototype = GetPrototype(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003678 return prototype->GetElement(index);
3679 }
3680
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003681 return GetElement(object, index);
3682}
3683
3684
lrn@chromium.org303ada72010-10-27 09:33:13 +00003685MaybeObject* Runtime::GetElement(Handle<Object> object, uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003686 return object->GetElement(index);
3687}
3688
3689
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003690MaybeObject* Runtime::GetObjectProperty(Isolate* isolate,
3691 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003692 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003693 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003694
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003695 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003696 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003697 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003698 isolate->factory()->NewTypeError("non_object_property_load",
3699 HandleVector(args, 2));
3700 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003701 }
3702
3703 // Check if the given key is an array index.
3704 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003705 if (key->ToArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003706 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003707 }
3708
3709 // Convert the key to a string - possibly by calling back into JavaScript.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003710 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003711 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003712 name = Handle<String>::cast(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003713 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003714 bool has_pending_exception = false;
3715 Handle<Object> converted =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003716 Execution::ToString(key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003717 if (has_pending_exception) return Failure::Exception();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003718 name = Handle<String>::cast(converted);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003719 }
3720
ager@chromium.org32912102009-01-16 10:38:43 +00003721 // Check if the name is trivially convertible to an index and get
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003722 // the element if so.
3723 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003724 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003725 } else {
3726 PropertyAttributes attr;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003727 return object->GetProperty(*name, &attr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003728 }
3729}
3730
3731
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003732RUNTIME_FUNCTION(MaybeObject*, Runtime_GetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003733 NoHandleAllocation ha;
3734 ASSERT(args.length() == 2);
3735
3736 Handle<Object> object = args.at<Object>(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003737 Handle<Object> key = args.at<Object>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003738
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003739 return Runtime::GetObjectProperty(isolate, object, key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003740}
3741
3742
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003743// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003744RUNTIME_FUNCTION(MaybeObject*, Runtime_KeyedGetProperty) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00003745 NoHandleAllocation ha;
3746 ASSERT(args.length() == 2);
3747
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003748 // Fast cases for getting named properties of the receiver JSObject
ager@chromium.org8bb60582008-12-11 12:02:20 +00003749 // itself.
3750 //
3751 // The global proxy objects has to be excluded since LocalLookup on
ager@chromium.org32912102009-01-16 10:38:43 +00003752 // the global proxy object can return a valid result even though the
ager@chromium.org8bb60582008-12-11 12:02:20 +00003753 // global proxy object never has properties. This is the case
3754 // because the global proxy object forwards everything to its hidden
3755 // prototype including local lookups.
3756 //
3757 // Additionally, we need to make sure that we do not cache results
3758 // for objects that require access checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003759 if (args[0]->IsJSObject() &&
3760 !args[0]->IsJSGlobalProxy() &&
ager@chromium.org8bb60582008-12-11 12:02:20 +00003761 !args[0]->IsAccessCheckNeeded() &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003762 args[1]->IsString()) {
3763 JSObject* receiver = JSObject::cast(args[0]);
3764 String* key = String::cast(args[1]);
3765 if (receiver->HasFastProperties()) {
3766 // Attempt to use lookup cache.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003767 Map* receiver_map = receiver->map();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003768 KeyedLookupCache* keyed_lookup_cache = isolate->keyed_lookup_cache();
3769 int offset = keyed_lookup_cache->Lookup(receiver_map, key);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00003770 if (offset != -1) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003771 Object* value = receiver->FastPropertyAt(offset);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003772 return value->IsTheHole() ? isolate->heap()->undefined_value() : value;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003773 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003774 // Lookup cache miss. Perform lookup and update the cache if appropriate.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003775 LookupResult result;
3776 receiver->LocalLookup(key, &result);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00003777 if (result.IsProperty() && result.type() == FIELD) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003778 int offset = result.GetFieldIndex();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003779 keyed_lookup_cache->Update(receiver_map, key, offset);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003780 return receiver->FastPropertyAt(offset);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003781 }
3782 } else {
3783 // Attempt dictionary lookup.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00003784 StringDictionary* dictionary = receiver->property_dictionary();
3785 int entry = dictionary->FindEntry(key);
3786 if ((entry != StringDictionary::kNotFound) &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003787 (dictionary->DetailsAt(entry).type() == NORMAL)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003788 Object* value = dictionary->ValueAt(entry);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003789 if (!receiver->IsGlobalObject()) return value;
3790 value = JSGlobalPropertyCell::cast(value)->value();
3791 if (!value->IsTheHole()) return value;
3792 // If value is the hole do the general lookup.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003793 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00003794 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003795 } else if (args[0]->IsString() && args[1]->IsSmi()) {
3796 // Fast case for string indexing using [] with a smi index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003797 HandleScope scope(isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003798 Handle<String> str = args.at<String>(0);
3799 int index = Smi::cast(args[1])->value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003800 if (index >= 0 && index < str->length()) {
3801 Handle<Object> result = GetCharAt(str, index);
3802 return *result;
3803 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00003804 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003805
3806 // Fall back to GetObjectProperty.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003807 return Runtime::GetObjectProperty(isolate,
3808 args.at<Object>(0),
ager@chromium.org7c537e22008-10-16 08:43:32 +00003809 args.at<Object>(1));
3810}
3811
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003812// Implements part of 8.12.9 DefineOwnProperty.
3813// There are 3 cases that lead here:
3814// Step 4b - define a new accessor property.
3815// Steps 9c & 12 - replace an existing data property with an accessor property.
3816// Step 12 - update an existing accessor property with an accessor or generic
3817// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003818RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineAccessorProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003819 ASSERT(args.length() == 5);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003820 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00003821 CONVERT_ARG_CHECKED(JSObject, obj, 0);
3822 CONVERT_CHECKED(String, name, args[1]);
3823 CONVERT_CHECKED(Smi, flag_setter, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003824 Object* fun = args[3];
3825 RUNTIME_ASSERT(fun->IsJSFunction() || fun->IsUndefined());
ager@chromium.org5c838252010-02-19 08:53:10 +00003826 CONVERT_CHECKED(Smi, flag_attr, args[4]);
3827 int unchecked = flag_attr->value();
3828 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3829 RUNTIME_ASSERT(!obj->IsNull());
3830 LookupResult result;
3831 obj->LocalLookupRealNamedProperty(name, &result);
3832
3833 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
3834 // If an existing property is either FIELD, NORMAL or CONSTANT_FUNCTION
3835 // delete it to avoid running into trouble in DefineAccessor, which
3836 // handles this incorrectly if the property is readonly (does nothing)
3837 if (result.IsProperty() &&
3838 (result.type() == FIELD || result.type() == NORMAL
3839 || result.type() == CONSTANT_FUNCTION)) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003840 Object* ok;
3841 { MaybeObject* maybe_ok =
3842 obj->DeleteProperty(name, JSObject::NORMAL_DELETION);
3843 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
3844 }
ager@chromium.org5c838252010-02-19 08:53:10 +00003845 }
3846 return obj->DefineAccessor(name, flag_setter->value() == 0, fun, attr);
3847}
3848
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003849// Implements part of 8.12.9 DefineOwnProperty.
3850// There are 3 cases that lead here:
3851// Step 4a - define a new data property.
3852// Steps 9b & 12 - replace an existing accessor property with a data property.
3853// Step 12 - update an existing data property with a data or generic
3854// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003855RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineDataProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003856 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003857 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00003858 CONVERT_ARG_CHECKED(JSObject, js_object, 0);
3859 CONVERT_ARG_CHECKED(String, name, 1);
3860 Handle<Object> obj_value = args.at<Object>(2);
3861
3862 CONVERT_CHECKED(Smi, flag, args[3]);
3863 int unchecked = flag->value();
3864 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3865
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003866 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
3867
3868 // Check if this is an element.
3869 uint32_t index;
3870 bool is_element = name->AsArrayIndex(&index);
3871
3872 // Special case for elements if any of the flags are true.
3873 // If elements are in fast case we always implicitly assume that:
3874 // DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
3875 if (((unchecked & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0) &&
3876 is_element) {
3877 // Normalize the elements to enable attributes on the property.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003878 if (js_object->IsJSGlobalProxy()) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003879 // We do not need to do access checks here since these has already
3880 // been performed by the call to GetOwnProperty.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003881 Handle<Object> proto(js_object->GetPrototype());
3882 // If proxy is detached, ignore the assignment. Alternatively,
3883 // we could throw an exception.
3884 if (proto->IsNull()) return *obj_value;
3885 js_object = Handle<JSObject>::cast(proto);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003886 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003887 NormalizeElements(js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003888 Handle<NumberDictionary> dictionary(js_object->element_dictionary());
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003889 // Make sure that we never go back to fast case.
3890 dictionary->set_requires_slow_elements();
3891 PropertyDetails details = PropertyDetails(attr, NORMAL);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003892 NumberDictionarySet(dictionary, index, obj_value, details);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003893 return *obj_value;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003894 }
3895
ager@chromium.org5c838252010-02-19 08:53:10 +00003896 LookupResult result;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003897 js_object->LookupRealNamedProperty(*name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00003898
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00003899 // To be compatible with safari we do not change the value on API objects
3900 // in defineProperty. Firefox disagrees here, and actually changes the value.
3901 if (result.IsProperty() &&
3902 (result.type() == CALLBACKS) &&
3903 result.GetCallbackObject()->IsAccessorInfo()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003904 return isolate->heap()->undefined_value();
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00003905 }
3906
ager@chromium.org5c838252010-02-19 08:53:10 +00003907 // Take special care when attributes are different and there is already
3908 // a property. For simplicity we normalize the property which enables us
3909 // to not worry about changing the instance_descriptor and creating a new
3910 // map. The current version of SetObjectProperty does not handle attributes
3911 // correctly in the case where a property is a field and is reset with
3912 // new attributes.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003913 if (result.IsProperty() &&
3914 (attr != result.GetAttributes() || result.type() == CALLBACKS)) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003915 // New attributes - normalize to avoid writing to instance descriptor
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003916 if (js_object->IsJSGlobalProxy()) {
3917 // Since the result is a property, the prototype will exist so
3918 // we don't have to check for null.
3919 js_object = Handle<JSObject>(JSObject::cast(js_object->GetPrototype()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003920 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003921 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00003922 // Use IgnoreAttributes version since a readonly property may be
3923 // overridden and SetProperty does not allow this.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003924 return js_object->SetLocalPropertyIgnoreAttributes(*name,
3925 *obj_value,
3926 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00003927 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003928
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003929 return Runtime::ForceSetObjectProperty(isolate,
3930 js_object,
3931 name,
3932 obj_value,
3933 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00003934}
3935
3936
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003937MaybeObject* Runtime::SetObjectProperty(Isolate* isolate,
3938 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003939 Handle<Object> key,
3940 Handle<Object> value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003941 PropertyAttributes attr,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003942 StrictModeFlag strict_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003943 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003944
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003945 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003946 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003947 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003948 isolate->factory()->NewTypeError("non_object_property_store",
3949 HandleVector(args, 2));
3950 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003951 }
3952
3953 // If the object isn't a JavaScript object, we ignore the store.
3954 if (!object->IsJSObject()) return *value;
3955
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003956 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
3957
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003958 // Check if the given key is an array index.
3959 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003960 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003961 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
3962 // of a string using [] notation. We need to support this too in
3963 // JavaScript.
3964 // In the case of a String object we just need to redirect the assignment to
3965 // the underlying string if the index is in range. Since the underlying
3966 // string does nothing with the assignment then we can ignore such
3967 // assignments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003968 if (js_object->IsStringObjectWithCharacterAt(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003969 return *value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003970 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003971
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003972 Handle<Object> result = SetElement(js_object, index, value, strict_mode);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003973 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003974 return *value;
3975 }
3976
3977 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003978 Handle<Object> result;
3979 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003980 result = SetElement(js_object, index, value, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003981 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003982 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003983 key_string->TryFlatten();
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003984 result = SetProperty(js_object, key_string, value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003985 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003986 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003987 return *value;
3988 }
3989
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003990 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003991 bool has_pending_exception = false;
3992 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
3993 if (has_pending_exception) return Failure::Exception();
3994 Handle<String> name = Handle<String>::cast(converted);
3995
3996 if (name->AsArrayIndex(&index)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003997 return js_object->SetElement(index, *value, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003998 } else {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003999 return js_object->SetProperty(*name, *value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004000 }
4001}
4002
4003
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004004MaybeObject* Runtime::ForceSetObjectProperty(Isolate* isolate,
4005 Handle<JSObject> js_object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004006 Handle<Object> key,
4007 Handle<Object> value,
4008 PropertyAttributes attr) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004009 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004010
4011 // Check if the given key is an array index.
4012 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004013 if (key->ToArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004014 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4015 // of a string using [] notation. We need to support this too in
4016 // JavaScript.
4017 // In the case of a String object we just need to redirect the assignment to
4018 // the underlying string if the index is in range. Since the underlying
4019 // string does nothing with the assignment then we can ignore such
4020 // assignments.
4021 if (js_object->IsStringObjectWithCharacterAt(index)) {
4022 return *value;
4023 }
4024
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004025 return js_object->SetElement(index, *value, kNonStrictMode);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004026 }
4027
4028 if (key->IsString()) {
4029 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004030 return js_object->SetElement(index, *value, kNonStrictMode);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004031 } else {
4032 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004033 key_string->TryFlatten();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004034 return js_object->SetLocalPropertyIgnoreAttributes(*key_string,
4035 *value,
4036 attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004037 }
4038 }
4039
4040 // Call-back into JavaScript to convert the key to a string.
4041 bool has_pending_exception = false;
4042 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4043 if (has_pending_exception) return Failure::Exception();
4044 Handle<String> name = Handle<String>::cast(converted);
4045
4046 if (name->AsArrayIndex(&index)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004047 return js_object->SetElement(index, *value, kNonStrictMode);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004048 } else {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004049 return js_object->SetLocalPropertyIgnoreAttributes(*name, *value, attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004050 }
4051}
4052
4053
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004054MaybeObject* Runtime::ForceDeleteObjectProperty(Isolate* isolate,
4055 Handle<JSObject> js_object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004056 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004057 HandleScope scope(isolate);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004058
4059 // Check if the given key is an array index.
4060 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004061 if (key->ToArrayIndex(&index)) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00004062 // In Firefox/SpiderMonkey, Safari and Opera you can access the
4063 // characters of a string using [] notation. In the case of a
4064 // String object we just need to redirect the deletion to the
4065 // underlying string if the index is in range. Since the
4066 // underlying string does nothing with the deletion, we can ignore
4067 // such deletions.
4068 if (js_object->IsStringObjectWithCharacterAt(index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004069 return isolate->heap()->true_value();
ager@chromium.orge2902be2009-06-08 12:21:35 +00004070 }
4071
4072 return js_object->DeleteElement(index, JSObject::FORCE_DELETION);
4073 }
4074
4075 Handle<String> key_string;
4076 if (key->IsString()) {
4077 key_string = Handle<String>::cast(key);
4078 } else {
4079 // Call-back into JavaScript to convert the key to a string.
4080 bool has_pending_exception = false;
4081 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4082 if (has_pending_exception) return Failure::Exception();
4083 key_string = Handle<String>::cast(converted);
4084 }
4085
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004086 key_string->TryFlatten();
ager@chromium.orge2902be2009-06-08 12:21:35 +00004087 return js_object->DeleteProperty(*key_string, JSObject::FORCE_DELETION);
4088}
4089
4090
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004091RUNTIME_FUNCTION(MaybeObject*, Runtime_SetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004092 NoHandleAllocation ha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004093 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004094
4095 Handle<Object> object = args.at<Object>(0);
4096 Handle<Object> key = args.at<Object>(1);
4097 Handle<Object> value = args.at<Object>(2);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004098 CONVERT_SMI_CHECKED(unchecked_attributes, args[3]);
4099 RUNTIME_ASSERT(
4100 (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004101 // Compute attributes.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004102 PropertyAttributes attributes =
4103 static_cast<PropertyAttributes>(unchecked_attributes);
4104
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004105 StrictModeFlag strict_mode = kNonStrictMode;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004106 if (args.length() == 5) {
4107 CONVERT_SMI_CHECKED(strict_unchecked, args[4]);
4108 RUNTIME_ASSERT(strict_unchecked == kStrictMode ||
4109 strict_unchecked == kNonStrictMode);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004110 strict_mode = static_cast<StrictModeFlag>(strict_unchecked);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004111 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004112
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004113 return Runtime::SetObjectProperty(isolate,
4114 object,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004115 key,
4116 value,
4117 attributes,
4118 strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004119}
4120
4121
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004122// Set the ES5 native flag on the function.
4123// This is used to decide if we should transform null and undefined
4124// into the global object when doing call and apply.
4125RUNTIME_FUNCTION(MaybeObject*, Runtime_SetES5Flag) {
4126 NoHandleAllocation ha;
4127 RUNTIME_ASSERT(args.length() == 1);
4128
4129 Handle<Object> object = args.at<Object>(0);
4130
4131 if (object->IsJSFunction()) {
4132 JSFunction* func = JSFunction::cast(*object);
4133 func->shared()->set_es5_native(true);
4134 }
4135 return isolate->heap()->undefined_value();
4136}
4137
4138
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004139// Set a local property, even if it is READ_ONLY. If the property does not
4140// exist, it will be added with attributes NONE.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004141RUNTIME_FUNCTION(MaybeObject*, Runtime_IgnoreAttributesAndSetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004142 NoHandleAllocation ha;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004143 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004144 CONVERT_CHECKED(JSObject, object, args[0]);
4145 CONVERT_CHECKED(String, name, args[1]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004146 // Compute attributes.
4147 PropertyAttributes attributes = NONE;
4148 if (args.length() == 4) {
4149 CONVERT_CHECKED(Smi, value_obj, args[3]);
4150 int unchecked_value = value_obj->value();
4151 // Only attribute bits should be set.
4152 RUNTIME_ASSERT(
4153 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4154 attributes = static_cast<PropertyAttributes>(unchecked_value);
4155 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004156
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004157 return object->
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004158 SetLocalPropertyIgnoreAttributes(name, args[2], attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004159}
4160
4161
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004162RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004163 NoHandleAllocation ha;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004164 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004165
4166 CONVERT_CHECKED(JSObject, object, args[0]);
4167 CONVERT_CHECKED(String, key, args[1]);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004168 CONVERT_SMI_CHECKED(strict, args[2]);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004169 return object->DeleteProperty(key, (strict == kStrictMode)
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004170 ? JSObject::STRICT_DELETION
4171 : JSObject::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004172}
4173
4174
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004175static Object* HasLocalPropertyImplementation(Isolate* isolate,
4176 Handle<JSObject> object,
ager@chromium.org9085a012009-05-11 19:22:57 +00004177 Handle<String> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004178 if (object->HasLocalProperty(*key)) return isolate->heap()->true_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004179 // Handle hidden prototypes. If there's a hidden prototype above this thing
4180 // then we have to check it for properties, because they are supposed to
4181 // look like they are on this object.
4182 Handle<Object> proto(object->GetPrototype());
4183 if (proto->IsJSObject() &&
4184 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004185 return HasLocalPropertyImplementation(isolate,
4186 Handle<JSObject>::cast(proto),
4187 key);
ager@chromium.org9085a012009-05-11 19:22:57 +00004188 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004189 return isolate->heap()->false_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004190}
4191
4192
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004193RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLocalProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004194 NoHandleAllocation ha;
4195 ASSERT(args.length() == 2);
4196 CONVERT_CHECKED(String, key, args[1]);
4197
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004198 uint32_t index;
4199 const bool key_is_array_index = key->AsArrayIndex(&index);
4200
ager@chromium.org9085a012009-05-11 19:22:57 +00004201 Object* obj = args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004202 // Only JS objects can have properties.
ager@chromium.org9085a012009-05-11 19:22:57 +00004203 if (obj->IsJSObject()) {
4204 JSObject* object = JSObject::cast(obj);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004205 // Fast case: either the key is a real named property or it is not
4206 // an array index and there are no interceptors or hidden
4207 // prototypes.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004208 if (object->HasRealNamedProperty(key)) return isolate->heap()->true_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004209 Map* map = object->map();
4210 if (!key_is_array_index &&
4211 !map->has_named_interceptor() &&
4212 !HeapObject::cast(map->prototype())->map()->is_hidden_prototype()) {
4213 return isolate->heap()->false_value();
4214 }
4215 // Slow case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004216 HandleScope scope(isolate);
4217 return HasLocalPropertyImplementation(isolate,
4218 Handle<JSObject>(object),
ager@chromium.org9085a012009-05-11 19:22:57 +00004219 Handle<String>(key));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004220 } else if (obj->IsString() && key_is_array_index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004221 // Well, there is one exception: Handle [] on strings.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004222 String* string = String::cast(obj);
4223 if (index < static_cast<uint32_t>(string->length())) {
4224 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004225 }
4226 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004227 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004228}
4229
4230
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004231RUNTIME_FUNCTION(MaybeObject*, Runtime_HasProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004232 NoHandleAllocation na;
4233 ASSERT(args.length() == 2);
4234
4235 // Only JS objects can have properties.
4236 if (args[0]->IsJSObject()) {
4237 JSObject* object = JSObject::cast(args[0]);
4238 CONVERT_CHECKED(String, key, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004239 if (object->HasProperty(key)) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004240 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004241 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004242}
4243
4244
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004245RUNTIME_FUNCTION(MaybeObject*, Runtime_HasElement) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004246 NoHandleAllocation na;
4247 ASSERT(args.length() == 2);
4248
4249 // Only JS objects can have elements.
4250 if (args[0]->IsJSObject()) {
4251 JSObject* object = JSObject::cast(args[0]);
4252 CONVERT_CHECKED(Smi, index_obj, args[1]);
4253 uint32_t index = index_obj->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004254 if (object->HasElement(index)) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004255 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004256 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004257}
4258
4259
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004260RUNTIME_FUNCTION(MaybeObject*, Runtime_IsPropertyEnumerable) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004261 NoHandleAllocation ha;
4262 ASSERT(args.length() == 2);
4263
4264 CONVERT_CHECKED(JSObject, object, args[0]);
4265 CONVERT_CHECKED(String, key, args[1]);
4266
4267 uint32_t index;
4268 if (key->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004269 return isolate->heap()->ToBoolean(object->HasElement(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004270 }
4271
ager@chromium.org870a0b62008-11-04 11:43:05 +00004272 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004273 return isolate->heap()->ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004274}
4275
4276
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004277RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004278 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004279 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00004280 CONVERT_ARG_CHECKED(JSObject, object, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004281 return *GetKeysFor(object);
4282}
4283
4284
4285// Returns either a FixedArray as Runtime_GetPropertyNames,
4286// or, if the given object has an enum cache that contains
4287// all enumerable properties of the object and its prototypes
4288// have none, the map of the object. This is used to speed up
4289// the check for deletions during a for-in.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004290RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNamesFast) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004291 ASSERT(args.length() == 1);
4292
4293 CONVERT_CHECKED(JSObject, raw_object, args[0]);
4294
4295 if (raw_object->IsSimpleEnum()) return raw_object->map();
4296
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004297 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004298 Handle<JSObject> object(raw_object);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004299 Handle<FixedArray> content = GetKeysInFixedArrayFor(object,
4300 INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004301
4302 // Test again, since cache may have been built by preceding call.
4303 if (object->IsSimpleEnum()) return object->map();
4304
4305 return *content;
4306}
4307
4308
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004309// Find the length of the prototype chain that is to to handled as one. If a
4310// prototype object is hidden it is to be viewed as part of the the object it
4311// is prototype for.
4312static int LocalPrototypeChainLength(JSObject* obj) {
4313 int count = 1;
4314 Object* proto = obj->GetPrototype();
4315 while (proto->IsJSObject() &&
4316 JSObject::cast(proto)->map()->is_hidden_prototype()) {
4317 count++;
4318 proto = JSObject::cast(proto)->GetPrototype();
4319 }
4320 return count;
4321}
4322
4323
4324// Return the names of the local named properties.
4325// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004326RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004327 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004328 ASSERT(args.length() == 1);
4329 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004330 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004331 }
4332 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4333
4334 // Skip the global proxy as it has no properties and always delegates to the
4335 // real global object.
4336 if (obj->IsJSGlobalProxy()) {
4337 // Only collect names if access is permitted.
4338 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004339 !isolate->MayNamedAccess(*obj,
4340 isolate->heap()->undefined_value(),
4341 v8::ACCESS_KEYS)) {
4342 isolate->ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
4343 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004344 }
4345 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
4346 }
4347
4348 // Find the number of objects making up this.
4349 int length = LocalPrototypeChainLength(*obj);
4350
4351 // Find the number of local properties for each of the objects.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00004352 ScopedVector<int> local_property_count(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004353 int total_property_count = 0;
4354 Handle<JSObject> jsproto = obj;
4355 for (int i = 0; i < length; i++) {
4356 // Only collect names if access is permitted.
4357 if (jsproto->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004358 !isolate->MayNamedAccess(*jsproto,
4359 isolate->heap()->undefined_value(),
4360 v8::ACCESS_KEYS)) {
4361 isolate->ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
4362 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004363 }
4364 int n;
4365 n = jsproto->NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE));
4366 local_property_count[i] = n;
4367 total_property_count += n;
4368 if (i < length - 1) {
4369 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4370 }
4371 }
4372
4373 // Allocate an array with storage for all the property names.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004374 Handle<FixedArray> names =
4375 isolate->factory()->NewFixedArray(total_property_count);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004376
4377 // Get the property names.
4378 jsproto = obj;
4379 int proto_with_hidden_properties = 0;
4380 for (int i = 0; i < length; i++) {
4381 jsproto->GetLocalPropertyNames(*names,
4382 i == 0 ? 0 : local_property_count[i - 1]);
4383 if (!GetHiddenProperties(jsproto, false)->IsUndefined()) {
4384 proto_with_hidden_properties++;
4385 }
4386 if (i < length - 1) {
4387 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4388 }
4389 }
4390
4391 // Filter out name of hidden propeties object.
4392 if (proto_with_hidden_properties > 0) {
4393 Handle<FixedArray> old_names = names;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004394 names = isolate->factory()->NewFixedArray(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004395 names->length() - proto_with_hidden_properties);
4396 int dest_pos = 0;
4397 for (int i = 0; i < total_property_count; i++) {
4398 Object* name = old_names->get(i);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004399 if (name == isolate->heap()->hidden_symbol()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004400 continue;
4401 }
4402 names->set(dest_pos++, name);
4403 }
4404 }
4405
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004406 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004407}
4408
4409
4410// Return the names of the local indexed properties.
4411// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004412RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004413 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004414 ASSERT(args.length() == 1);
4415 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004416 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004417 }
4418 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4419
4420 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004421 Handle<FixedArray> names = isolate->factory()->NewFixedArray(n);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004422 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004423 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004424}
4425
4426
4427// Return information on whether an object has a named or indexed interceptor.
4428// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004429RUNTIME_FUNCTION(MaybeObject*, Runtime_GetInterceptorInfo) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004430 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004431 ASSERT(args.length() == 1);
4432 if (!args[0]->IsJSObject()) {
4433 return Smi::FromInt(0);
4434 }
4435 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4436
4437 int result = 0;
4438 if (obj->HasNamedInterceptor()) result |= 2;
4439 if (obj->HasIndexedInterceptor()) result |= 1;
4440
4441 return Smi::FromInt(result);
4442}
4443
4444
4445// Return property names from named interceptor.
4446// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004447RUNTIME_FUNCTION(MaybeObject*, Runtime_GetNamedInterceptorPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004448 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004449 ASSERT(args.length() == 1);
4450 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4451
4452 if (obj->HasNamedInterceptor()) {
4453 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
4454 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4455 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004456 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004457}
4458
4459
4460// Return element names from indexed interceptor.
4461// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004462RUNTIME_FUNCTION(MaybeObject*, Runtime_GetIndexedInterceptorElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004463 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004464 ASSERT(args.length() == 1);
4465 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4466
4467 if (obj->HasIndexedInterceptor()) {
4468 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
4469 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4470 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004471 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004472}
4473
4474
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004475RUNTIME_FUNCTION(MaybeObject*, Runtime_LocalKeys) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004476 ASSERT_EQ(args.length(), 1);
4477 CONVERT_CHECKED(JSObject, raw_object, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004478 HandleScope scope(isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004479 Handle<JSObject> object(raw_object);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004480
4481 if (object->IsJSGlobalProxy()) {
ricow@chromium.org65001782011-02-15 13:36:41 +00004482 // Do access checks before going to the global object.
4483 if (object->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004484 !isolate->MayNamedAccess(*object, isolate->heap()->undefined_value(),
ricow@chromium.org65001782011-02-15 13:36:41 +00004485 v8::ACCESS_KEYS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004486 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_KEYS);
4487 return *isolate->factory()->NewJSArray(0);
ricow@chromium.org65001782011-02-15 13:36:41 +00004488 }
4489
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004490 Handle<Object> proto(object->GetPrototype());
4491 // If proxy is detached we simply return an empty array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004492 if (proto->IsNull()) return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004493 object = Handle<JSObject>::cast(proto);
4494 }
4495
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004496 Handle<FixedArray> contents = GetKeysInFixedArrayFor(object,
4497 LOCAL_ONLY);
4498 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
4499 // property array and since the result is mutable we have to create
4500 // a fresh clone on each invocation.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004501 int length = contents->length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004502 Handle<FixedArray> copy = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004503 for (int i = 0; i < length; i++) {
4504 Object* entry = contents->get(i);
4505 if (entry->IsString()) {
4506 copy->set(i, entry);
4507 } else {
4508 ASSERT(entry->IsNumber());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004509 HandleScope scope(isolate);
4510 Handle<Object> entry_handle(entry, isolate);
4511 Handle<Object> entry_str =
4512 isolate->factory()->NumberToString(entry_handle);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004513 copy->set(i, *entry_str);
4514 }
4515 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004516 return *isolate->factory()->NewJSArrayWithElements(copy);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004517}
4518
4519
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004520RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArgumentsProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004521 NoHandleAllocation ha;
4522 ASSERT(args.length() == 1);
4523
4524 // Compute the frame holding the arguments.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00004525 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004526 it.AdvanceToArgumentsFrame();
4527 JavaScriptFrame* frame = it.frame();
4528
4529 // Get the actual number of provided arguments.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00004530 const uint32_t n = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004531
4532 // Try to convert the key to an index. If successful and within
4533 // index return the the argument from the frame.
4534 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004535 if (args[0]->ToArrayIndex(&index) && index < n) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004536 return frame->GetParameter(index);
4537 }
4538
4539 // Convert the key to a string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004540 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004541 bool exception = false;
4542 Handle<Object> converted =
4543 Execution::ToString(args.at<Object>(0), &exception);
4544 if (exception) return Failure::Exception();
4545 Handle<String> key = Handle<String>::cast(converted);
4546
4547 // Try to convert the string key into an array index.
4548 if (key->AsArrayIndex(&index)) {
4549 if (index < n) {
4550 return frame->GetParameter(index);
4551 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004552 return isolate->initial_object_prototype()->GetElement(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004553 }
4554 }
4555
4556 // Handle special arguments properties.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004557 if (key->Equals(isolate->heap()->length_symbol())) return Smi::FromInt(n);
4558 if (key->Equals(isolate->heap()->callee_symbol())) {
4559 Object* function = frame->function();
4560 if (function->IsJSFunction() &&
4561 JSFunction::cast(function)->shared()->strict_mode()) {
4562 return isolate->Throw(*isolate->factory()->NewTypeError(
4563 "strict_arguments_callee", HandleVector<Object>(NULL, 0)));
4564 }
4565 return function;
4566 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004567
4568 // Lookup in the initial Object.prototype object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004569 return isolate->initial_object_prototype()->GetProperty(*key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004570}
4571
4572
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004573RUNTIME_FUNCTION(MaybeObject*, Runtime_ToFastProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004574 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004575
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004576 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004577 Handle<Object> object = args.at<Object>(0);
4578 if (object->IsJSObject()) {
4579 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
ager@chromium.org5c838252010-02-19 08:53:10 +00004580 if (!js_object->HasFastProperties() && !js_object->IsGlobalObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004581 MaybeObject* ok = js_object->TransformToFastProperties(0);
4582 if (ok->IsRetryAfterGC()) return ok;
ager@chromium.org5c838252010-02-19 08:53:10 +00004583 }
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004584 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004585 return *object;
4586}
4587
4588
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004589RUNTIME_FUNCTION(MaybeObject*, Runtime_ToSlowProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004590 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004591
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004592 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004593 Handle<Object> object = args.at<Object>(0);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004594 if (object->IsJSObject() && !object->IsJSGlobalProxy()) {
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004595 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004596 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004597 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004598 return *object;
4599}
4600
4601
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004602RUNTIME_FUNCTION(MaybeObject*, Runtime_ToBool) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004603 NoHandleAllocation ha;
4604 ASSERT(args.length() == 1);
4605
4606 return args[0]->ToBoolean();
4607}
4608
4609
4610// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
4611// Possible optimizations: put the type string into the oddballs.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004612RUNTIME_FUNCTION(MaybeObject*, Runtime_Typeof) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004613 NoHandleAllocation ha;
4614
4615 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004616 if (obj->IsNumber()) return isolate->heap()->number_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004617 HeapObject* heap_obj = HeapObject::cast(obj);
4618
4619 // typeof an undetectable object is 'undefined'
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004620 if (heap_obj->map()->is_undetectable()) {
4621 return isolate->heap()->undefined_symbol();
4622 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004623
4624 InstanceType instance_type = heap_obj->map()->instance_type();
4625 if (instance_type < FIRST_NONSTRING_TYPE) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004626 return isolate->heap()->string_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004627 }
4628
4629 switch (instance_type) {
4630 case ODDBALL_TYPE:
4631 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004632 return isolate->heap()->boolean_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004633 }
4634 if (heap_obj->IsNull()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004635 return isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004636 }
4637 ASSERT(heap_obj->IsUndefined());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004638 return isolate->heap()->undefined_symbol();
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00004639 case JS_FUNCTION_TYPE: case JS_REGEXP_TYPE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004640 return isolate->heap()->function_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004641 default:
4642 // For any kind of object not handled above, the spec rule for
4643 // host objects gives that it is okay to return "object"
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004644 return isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004645 }
4646}
4647
4648
lrn@chromium.org25156de2010-04-06 13:10:27 +00004649static bool AreDigits(const char*s, int from, int to) {
4650 for (int i = from; i < to; i++) {
4651 if (s[i] < '0' || s[i] > '9') return false;
4652 }
4653
4654 return true;
4655}
4656
4657
4658static int ParseDecimalInteger(const char*s, int from, int to) {
4659 ASSERT(to - from < 10); // Overflow is not possible.
4660 ASSERT(from < to);
4661 int d = s[from] - '0';
4662
4663 for (int i = from + 1; i < to; i++) {
4664 d = 10 * d + (s[i] - '0');
4665 }
4666
4667 return d;
4668}
4669
4670
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004671RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004672 NoHandleAllocation ha;
4673 ASSERT(args.length() == 1);
4674 CONVERT_CHECKED(String, subject, args[0]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004675 subject->TryFlatten();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004676
4677 // Fast case: short integer or some sorts of junk values.
4678 int len = subject->length();
4679 if (subject->IsSeqAsciiString()) {
4680 if (len == 0) return Smi::FromInt(0);
4681
4682 char const* data = SeqAsciiString::cast(subject)->GetChars();
4683 bool minus = (data[0] == '-');
4684 int start_pos = (minus ? 1 : 0);
4685
4686 if (start_pos == len) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004687 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004688 } else if (data[start_pos] > '9') {
4689 // Fast check for a junk value. A valid string may start from a
4690 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
4691 // the 'I' character ('Infinity'). All of that have codes not greater than
4692 // '9' except 'I'.
4693 if (data[start_pos] != 'I') {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004694 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004695 }
4696 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
4697 // The maximal/minimal smi has 10 digits. If the string has less digits we
4698 // know it will fit into the smi-data type.
4699 int d = ParseDecimalInteger(data, start_pos, len);
4700 if (minus) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004701 if (d == 0) return isolate->heap()->minus_zero_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004702 d = -d;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004703 } else if (!subject->HasHashCode() &&
4704 len <= String::kMaxArrayIndexSize &&
4705 (len == 1 || data[0] != '0')) {
4706 // String hash is not calculated yet but all the data are present.
4707 // Update the hash field to speed up sequential convertions.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00004708 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004709#ifdef DEBUG
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004710 subject->Hash(); // Force hash calculation.
4711 ASSERT_EQ(static_cast<int>(subject->hash_field()),
4712 static_cast<int>(hash));
4713#endif
4714 subject->set_hash_field(hash);
lrn@chromium.org25156de2010-04-06 13:10:27 +00004715 }
4716 return Smi::FromInt(d);
4717 }
4718 }
4719
4720 // Slower case.
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00004721 return isolate->heap()->NumberFromDouble(
4722 StringToDouble(isolate->unicode_cache(), subject, ALLOW_HEX));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004723}
4724
4725
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004726RUNTIME_FUNCTION(MaybeObject*, Runtime_StringFromCharCodeArray) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004727 NoHandleAllocation ha;
4728 ASSERT(args.length() == 1);
4729
4730 CONVERT_CHECKED(JSArray, codes, args[0]);
4731 int length = Smi::cast(codes->length())->value();
4732
4733 // Check if the string can be ASCII.
4734 int i;
4735 for (i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004736 Object* element;
4737 { MaybeObject* maybe_element = codes->GetElement(i);
4738 // We probably can't get an exception here, but just in order to enforce
4739 // the checking of inputs in the runtime calls we check here.
4740 if (!maybe_element->ToObject(&element)) return maybe_element;
4741 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004742 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
4743 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
4744 break;
4745 }
4746
lrn@chromium.org303ada72010-10-27 09:33:13 +00004747 MaybeObject* maybe_object = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004748 if (i == length) { // The string is ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004749 maybe_object = isolate->heap()->AllocateRawAsciiString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004750 } else { // The string is not ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004751 maybe_object = isolate->heap()->AllocateRawTwoByteString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004752 }
4753
lrn@chromium.org303ada72010-10-27 09:33:13 +00004754 Object* object = NULL;
4755 if (!maybe_object->ToObject(&object)) return maybe_object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004756 String* result = String::cast(object);
4757 for (int i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004758 Object* element;
4759 { MaybeObject* maybe_element = codes->GetElement(i);
4760 if (!maybe_element->ToObject(&element)) return maybe_element;
4761 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004762 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004763 result->Set(i, chr & 0xffff);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004764 }
4765 return result;
4766}
4767
4768
4769// kNotEscaped is generated by the following:
4770//
4771// #!/bin/perl
4772// for (my $i = 0; $i < 256; $i++) {
4773// print "\n" if $i % 16 == 0;
4774// my $c = chr($i);
4775// my $escaped = 1;
4776// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
4777// print $escaped ? "0, " : "1, ";
4778// }
4779
4780
4781static bool IsNotEscaped(uint16_t character) {
4782 // Only for 8 bit characters, the rest are always escaped (in a different way)
4783 ASSERT(character < 256);
4784 static const char kNotEscaped[256] = {
4785 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4786 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4787 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
4788 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
4789 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4790 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
4791 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4792 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
4793 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4794 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4795 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4796 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4797 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4798 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4799 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4800 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4801 };
4802 return kNotEscaped[character] != 0;
4803}
4804
4805
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004806RUNTIME_FUNCTION(MaybeObject*, Runtime_URIEscape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004807 const char hex_chars[] = "0123456789ABCDEF";
4808 NoHandleAllocation ha;
4809 ASSERT(args.length() == 1);
4810 CONVERT_CHECKED(String, source, args[0]);
4811
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004812 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004813
4814 int escaped_length = 0;
4815 int length = source->length();
4816 {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004817 Access<StringInputBuffer> buffer(
4818 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004819 buffer->Reset(source);
4820 while (buffer->has_more()) {
4821 uint16_t character = buffer->GetNext();
4822 if (character >= 256) {
4823 escaped_length += 6;
4824 } else if (IsNotEscaped(character)) {
4825 escaped_length++;
4826 } else {
4827 escaped_length += 3;
4828 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004829 // We don't allow strings that are longer than a maximal length.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004830 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004831 if (escaped_length > String::kMaxLength) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004832 isolate->context()->mark_out_of_memory();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004833 return Failure::OutOfMemoryException();
4834 }
4835 }
4836 }
4837 // No length change implies no change. Return original string if no change.
4838 if (escaped_length == length) {
4839 return source;
4840 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00004841 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004842 { MaybeObject* maybe_o =
4843 isolate->heap()->AllocateRawAsciiString(escaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004844 if (!maybe_o->ToObject(&o)) return maybe_o;
4845 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004846 String* destination = String::cast(o);
4847 int dest_position = 0;
4848
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004849 Access<StringInputBuffer> buffer(
4850 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004851 buffer->Rewind();
4852 while (buffer->has_more()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00004853 uint16_t chr = buffer->GetNext();
4854 if (chr >= 256) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004855 destination->Set(dest_position, '%');
4856 destination->Set(dest_position+1, 'u');
4857 destination->Set(dest_position+2, hex_chars[chr >> 12]);
4858 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]);
4859 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]);
4860 destination->Set(dest_position+5, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004861 dest_position += 6;
ager@chromium.org870a0b62008-11-04 11:43:05 +00004862 } else if (IsNotEscaped(chr)) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004863 destination->Set(dest_position, chr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004864 dest_position++;
4865 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004866 destination->Set(dest_position, '%');
4867 destination->Set(dest_position+1, hex_chars[chr >> 4]);
4868 destination->Set(dest_position+2, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004869 dest_position += 3;
4870 }
4871 }
4872 return destination;
4873}
4874
4875
4876static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
4877 static const signed char kHexValue['g'] = {
4878 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4879 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4880 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4881 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
4882 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4883 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4884 -1, 10, 11, 12, 13, 14, 15 };
4885
4886 if (character1 > 'f') return -1;
4887 int hi = kHexValue[character1];
4888 if (hi == -1) return -1;
4889 if (character2 > 'f') return -1;
4890 int lo = kHexValue[character2];
4891 if (lo == -1) return -1;
4892 return (hi << 4) + lo;
4893}
4894
4895
ager@chromium.org870a0b62008-11-04 11:43:05 +00004896static inline int Unescape(String* source,
ager@chromium.org870a0b62008-11-04 11:43:05 +00004897 int i,
4898 int length,
4899 int* step) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004900 uint16_t character = source->Get(i);
ager@chromium.org870a0b62008-11-04 11:43:05 +00004901 int32_t hi = 0;
4902 int32_t lo = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004903 if (character == '%' &&
4904 i <= length - 6 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004905 source->Get(i + 1) == 'u' &&
4906 (hi = TwoDigitHex(source->Get(i + 2),
4907 source->Get(i + 3))) != -1 &&
4908 (lo = TwoDigitHex(source->Get(i + 4),
4909 source->Get(i + 5))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004910 *step = 6;
4911 return (hi << 8) + lo;
4912 } else if (character == '%' &&
4913 i <= length - 3 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004914 (lo = TwoDigitHex(source->Get(i + 1),
4915 source->Get(i + 2))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004916 *step = 3;
4917 return lo;
4918 } else {
4919 *step = 1;
4920 return character;
4921 }
4922}
4923
4924
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004925RUNTIME_FUNCTION(MaybeObject*, Runtime_URIUnescape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004926 NoHandleAllocation ha;
4927 ASSERT(args.length() == 1);
4928 CONVERT_CHECKED(String, source, args[0]);
4929
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004930 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004931
4932 bool ascii = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004933 int length = source->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004934
4935 int unescaped_length = 0;
4936 for (int i = 0; i < length; unescaped_length++) {
4937 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004938 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004939 ascii = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004940 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004941 i += step;
4942 }
4943
4944 // No length change implies no change. Return original string if no change.
4945 if (unescaped_length == length)
4946 return source;
4947
lrn@chromium.org303ada72010-10-27 09:33:13 +00004948 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004949 { MaybeObject* maybe_o =
4950 ascii ?
4951 isolate->heap()->AllocateRawAsciiString(unescaped_length) :
4952 isolate->heap()->AllocateRawTwoByteString(unescaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004953 if (!maybe_o->ToObject(&o)) return maybe_o;
4954 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004955 String* destination = String::cast(o);
4956
4957 int dest_position = 0;
4958 for (int i = 0; i < length; dest_position++) {
4959 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004960 destination->Set(dest_position, Unescape(source, i, length, &step));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004961 i += step;
4962 }
4963 return destination;
4964}
4965
4966
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004967static const unsigned int kQuoteTableLength = 128u;
4968
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004969static const int kJsonQuotesCharactersPerEntry = 8;
4970static const char* const JsonQuotes =
4971 "\\u0000 \\u0001 \\u0002 \\u0003 "
4972 "\\u0004 \\u0005 \\u0006 \\u0007 "
4973 "\\b \\t \\n \\u000b "
4974 "\\f \\r \\u000e \\u000f "
4975 "\\u0010 \\u0011 \\u0012 \\u0013 "
4976 "\\u0014 \\u0015 \\u0016 \\u0017 "
4977 "\\u0018 \\u0019 \\u001a \\u001b "
4978 "\\u001c \\u001d \\u001e \\u001f "
4979 " ! \\\" # "
4980 "$ % & ' "
4981 "( ) * + "
4982 ", - . / "
4983 "0 1 2 3 "
4984 "4 5 6 7 "
4985 "8 9 : ; "
4986 "< = > ? "
4987 "@ A B C "
4988 "D E F G "
4989 "H I J K "
4990 "L M N O "
4991 "P Q R S "
4992 "T U V W "
4993 "X Y Z [ "
4994 "\\\\ ] ^ _ "
4995 "` a b c "
4996 "d e f g "
4997 "h i j k "
4998 "l m n o "
4999 "p q r s "
5000 "t u v w "
5001 "x y z { "
5002 "| } ~ \177 ";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005003
5004
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005005// For a string that is less than 32k characters it should always be
5006// possible to allocate it in new space.
5007static const int kMaxGuaranteedNewSpaceString = 32 * 1024;
5008
5009
5010// Doing JSON quoting cannot make the string more than this many times larger.
5011static const int kJsonQuoteWorstCaseBlowup = 6;
5012
5013
5014// Covers the entire ASCII range (all other characters are unchanged by JSON
5015// quoting).
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005016static const byte JsonQuoteLengths[kQuoteTableLength] = {
5017 6, 6, 6, 6, 6, 6, 6, 6,
5018 2, 2, 2, 6, 2, 2, 6, 6,
5019 6, 6, 6, 6, 6, 6, 6, 6,
5020 6, 6, 6, 6, 6, 6, 6, 6,
5021 1, 1, 2, 1, 1, 1, 1, 1,
5022 1, 1, 1, 1, 1, 1, 1, 1,
5023 1, 1, 1, 1, 1, 1, 1, 1,
5024 1, 1, 1, 1, 1, 1, 1, 1,
5025 1, 1, 1, 1, 1, 1, 1, 1,
5026 1, 1, 1, 1, 1, 1, 1, 1,
5027 1, 1, 1, 1, 1, 1, 1, 1,
5028 1, 1, 1, 1, 2, 1, 1, 1,
5029 1, 1, 1, 1, 1, 1, 1, 1,
5030 1, 1, 1, 1, 1, 1, 1, 1,
5031 1, 1, 1, 1, 1, 1, 1, 1,
5032 1, 1, 1, 1, 1, 1, 1, 1,
5033};
5034
5035
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005036template <typename StringType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005037MaybeObject* AllocateRawString(Isolate* isolate, int length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005038
5039
5040template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005041MaybeObject* AllocateRawString<SeqTwoByteString>(Isolate* isolate, int length) {
5042 return isolate->heap()->AllocateRawTwoByteString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005043}
5044
5045
5046template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005047MaybeObject* AllocateRawString<SeqAsciiString>(Isolate* isolate, int length) {
5048 return isolate->heap()->AllocateRawAsciiString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005049}
5050
5051
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005052template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005053static MaybeObject* SlowQuoteJsonString(Isolate* isolate,
5054 Vector<const Char> characters) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005055 int length = characters.length();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005056 const Char* read_cursor = characters.start();
5057 const Char* end = read_cursor + length;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005058 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005059 int quoted_length = kSpaceForQuotes;
5060 while (read_cursor < end) {
5061 Char c = *(read_cursor++);
5062 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5063 quoted_length++;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005064 } else {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005065 quoted_length += JsonQuoteLengths[static_cast<unsigned>(c)];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005066 }
5067 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005068 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5069 quoted_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005070 Object* new_object;
5071 if (!new_alloc->ToObject(&new_object)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005072 return new_alloc;
5073 }
5074 StringType* new_string = StringType::cast(new_object);
5075
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005076 Char* write_cursor = reinterpret_cast<Char*>(
5077 new_string->address() + SeqAsciiString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005078 if (comma) *(write_cursor++) = ',';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005079 *(write_cursor++) = '"';
5080
5081 read_cursor = characters.start();
5082 while (read_cursor < end) {
5083 Char c = *(read_cursor++);
5084 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5085 *(write_cursor++) = c;
5086 } else {
5087 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5088 const char* replacement = JsonQuotes +
5089 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5090 for (int i = 0; i < len; i++) {
5091 *write_cursor++ = *replacement++;
5092 }
5093 }
5094 }
5095 *(write_cursor++) = '"';
5096 return new_string;
5097}
5098
5099
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005100template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005101static MaybeObject* QuoteJsonString(Isolate* isolate,
5102 Vector<const Char> characters) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005103 int length = characters.length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005104 isolate->counters()->quote_json_char_count()->Increment(length);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005105 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005106 int worst_case_length = length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotes;
5107 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005108 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005109 }
5110
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005111 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5112 worst_case_length);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005113 Object* new_object;
5114 if (!new_alloc->ToObject(&new_object)) {
5115 return new_alloc;
5116 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005117 if (!isolate->heap()->new_space()->Contains(new_object)) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005118 // Even if our string is small enough to fit in new space we still have to
5119 // handle it being allocated in old space as may happen in the third
5120 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5121 // CEntryStub::GenerateCore.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005122 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005123 }
5124 StringType* new_string = StringType::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005125 ASSERT(isolate->heap()->new_space()->Contains(new_string));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005126
5127 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize);
5128 Char* write_cursor = reinterpret_cast<Char*>(
5129 new_string->address() + SeqAsciiString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005130 if (comma) *(write_cursor++) = ',';
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005131 *(write_cursor++) = '"';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005132
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005133 const Char* read_cursor = characters.start();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005134 const Char* end = read_cursor + length;
5135 while (read_cursor < end) {
5136 Char c = *(read_cursor++);
5137 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5138 *(write_cursor++) = c;
5139 } else {
5140 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5141 const char* replacement = JsonQuotes +
5142 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5143 write_cursor[0] = replacement[0];
5144 if (len > 1) {
5145 write_cursor[1] = replacement[1];
5146 if (len > 2) {
5147 ASSERT(len == 6);
5148 write_cursor[2] = replacement[2];
5149 write_cursor[3] = replacement[3];
5150 write_cursor[4] = replacement[4];
5151 write_cursor[5] = replacement[5];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005152 }
5153 }
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005154 write_cursor += len;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005155 }
5156 }
5157 *(write_cursor++) = '"';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005158
5159 int final_length = static_cast<int>(
5160 write_cursor - reinterpret_cast<Char*>(
5161 new_string->address() + SeqAsciiString::kHeaderSize));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005162 isolate->heap()->new_space()->
5163 template ShrinkStringAtAllocationBoundary<StringType>(
5164 new_string, final_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005165 return new_string;
5166}
5167
5168
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005169RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONString) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005170 NoHandleAllocation ha;
5171 CONVERT_CHECKED(String, str, args[0]);
5172 if (!str->IsFlat()) {
5173 MaybeObject* try_flatten = str->TryFlatten();
5174 Object* flat;
5175 if (!try_flatten->ToObject(&flat)) {
5176 return try_flatten;
5177 }
5178 str = String::cast(flat);
5179 ASSERT(str->IsFlat());
5180 }
5181 if (str->IsTwoByteRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005182 return QuoteJsonString<uc16, SeqTwoByteString, false>(isolate,
5183 str->ToUC16Vector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005184 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005185 return QuoteJsonString<char, SeqAsciiString, false>(isolate,
5186 str->ToAsciiVector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005187 }
5188}
5189
5190
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005191RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringComma) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005192 NoHandleAllocation ha;
5193 CONVERT_CHECKED(String, str, args[0]);
5194 if (!str->IsFlat()) {
5195 MaybeObject* try_flatten = str->TryFlatten();
5196 Object* flat;
5197 if (!try_flatten->ToObject(&flat)) {
5198 return try_flatten;
5199 }
5200 str = String::cast(flat);
5201 ASSERT(str->IsFlat());
5202 }
5203 if (str->IsTwoByteRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005204 return QuoteJsonString<uc16, SeqTwoByteString, true>(isolate,
5205 str->ToUC16Vector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005206 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005207 return QuoteJsonString<char, SeqAsciiString, true>(isolate,
5208 str->ToAsciiVector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005209 }
5210}
5211
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005212RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseInt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005213 NoHandleAllocation ha;
5214
5215 CONVERT_CHECKED(String, s, args[0]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005216 CONVERT_SMI_CHECKED(radix, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005217
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005218 s->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005219
lrn@chromium.org25156de2010-04-06 13:10:27 +00005220 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005221 double value = StringToInt(isolate->unicode_cache(), s, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005222 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005223}
5224
5225
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005226RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseFloat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005227 NoHandleAllocation ha;
5228 CONVERT_CHECKED(String, str, args[0]);
5229
5230 // ECMA-262 section 15.1.2.3, empty string is NaN
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005231 double value = StringToDouble(isolate->unicode_cache(),
5232 str, ALLOW_TRAILING_JUNK, OS::nan_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005233
5234 // Create a number object from the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005235 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005236}
5237
5238
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005239template <class Converter>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005240MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005241 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00005242 String* s,
5243 int length,
5244 int input_string_length,
5245 unibrow::Mapping<Converter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005246 // We try this twice, once with the assumption that the result is no longer
5247 // than the input and, if that assumption breaks, again with the exact
5248 // length. This may not be pretty, but it is nicer than what was here before
5249 // and I hereby claim my vaffel-is.
5250 //
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005251 // Allocate the resulting string.
5252 //
5253 // NOTE: This assumes that the upper/lower case of an ascii
5254 // character is also ascii. This is currently the case, but it
5255 // might break in the future if we implement more context and locale
5256 // dependent upper/lower conversions.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005257 Object* o;
5258 { MaybeObject* maybe_o = s->IsAsciiRepresentation()
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005259 ? isolate->heap()->AllocateRawAsciiString(length)
5260 : isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005261 if (!maybe_o->ToObject(&o)) return maybe_o;
5262 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005263 String* result = String::cast(o);
5264 bool has_changed_character = false;
5265
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005266 // Convert all characters to upper case, assuming that they will fit
5267 // in the buffer
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005268 Access<StringInputBuffer> buffer(
5269 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005270 buffer->Reset(s);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005271 unibrow::uchar chars[Converter::kMaxWidth];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005272 // We can assume that the string is not empty
5273 uc32 current = buffer->GetNext();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005274 for (int i = 0; i < length;) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00005275 bool has_next = buffer->has_more();
5276 uc32 next = has_next ? buffer->GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005277 int char_length = mapping->get(current, next, chars);
5278 if (char_length == 0) {
5279 // The case conversion of this character is the character itself.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005280 result->Set(i, current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005281 i++;
5282 } else if (char_length == 1) {
5283 // Common case: converting the letter resulted in one character.
5284 ASSERT(static_cast<uc32>(chars[0]) != current);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005285 result->Set(i, chars[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005286 has_changed_character = true;
5287 i++;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005288 } else if (length == input_string_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005289 // We've assumed that the result would be as long as the
5290 // input but here is a character that converts to several
5291 // characters. No matter, we calculate the exact length
5292 // of the result and try the whole thing again.
5293 //
5294 // Note that this leaves room for optimization. We could just
5295 // memcpy what we already have to the result string. Also,
5296 // the result string is the last object allocated we could
5297 // "realloc" it and probably, in the vast majority of cases,
5298 // extend the existing string to be able to hold the full
5299 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00005300 int next_length = 0;
5301 if (has_next) {
5302 next_length = mapping->get(next, 0, chars);
5303 if (next_length == 0) next_length = 1;
5304 }
5305 int current_length = i + char_length + next_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005306 while (buffer->has_more()) {
5307 current = buffer->GetNext();
ager@chromium.org7c537e22008-10-16 08:43:32 +00005308 // NOTE: we use 0 as the next character here because, while
5309 // the next character may affect what a character converts to,
5310 // it does not in any case affect the length of what it convert
5311 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005312 int char_length = mapping->get(current, 0, chars);
5313 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00005314 current_length += char_length;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005315 if (current_length > Smi::kMaxValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005316 isolate->context()->mark_out_of_memory();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005317 return Failure::OutOfMemoryException();
5318 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005319 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005320 // Try again with the real length.
5321 return Smi::FromInt(current_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005322 } else {
5323 for (int j = 0; j < char_length; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005324 result->Set(i, chars[j]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005325 i++;
5326 }
5327 has_changed_character = true;
5328 }
5329 current = next;
5330 }
5331 if (has_changed_character) {
5332 return result;
5333 } else {
5334 // If we didn't actually change anything in doing the conversion
5335 // we simple return the result and let the converted string
5336 // become garbage; there is no reason to keep two identical strings
5337 // alive.
5338 return s;
5339 }
5340}
5341
5342
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005343namespace {
5344
lrn@chromium.org303ada72010-10-27 09:33:13 +00005345static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF;
5346
5347
5348// Given a word and two range boundaries returns a word with high bit
5349// set in every byte iff the corresponding input byte was strictly in
5350// the range (m, n). All the other bits in the result are cleared.
5351// This function is only useful when it can be inlined and the
5352// boundaries are statically known.
5353// Requires: all bytes in the input word and the boundaries must be
5354// ascii (less than 0x7F).
5355static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
5356 // Every byte in an ascii string is less than or equal to 0x7F.
5357 ASSERT((w & (kOneInEveryByte * 0x7F)) == w);
5358 // Use strict inequalities since in edge cases the function could be
5359 // further simplified.
5360 ASSERT(0 < m && m < n && n < 0x7F);
5361 // Has high bit set in every w byte less than n.
5362 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w;
5363 // Has high bit set in every w byte greater than m.
5364 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m);
5365 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80));
5366}
5367
5368
5369enum AsciiCaseConversion {
5370 ASCII_TO_LOWER,
5371 ASCII_TO_UPPER
5372};
5373
5374
5375template <AsciiCaseConversion dir>
5376struct FastAsciiConverter {
5377 static bool Convert(char* dst, char* src, int length) {
5378#ifdef DEBUG
5379 char* saved_dst = dst;
5380 char* saved_src = src;
5381#endif
5382 // We rely on the distance between upper and lower case letters
5383 // being a known power of 2.
5384 ASSERT('a' - 'A' == (1 << 5));
5385 // Boundaries for the range of input characters than require conversion.
5386 const char lo = (dir == ASCII_TO_LOWER) ? 'A' - 1 : 'a' - 1;
5387 const char hi = (dir == ASCII_TO_LOWER) ? 'Z' + 1 : 'z' + 1;
5388 bool changed = false;
5389 char* const limit = src + length;
5390#ifdef V8_HOST_CAN_READ_UNALIGNED
5391 // Process the prefix of the input that requires no conversion one
5392 // (machine) word at a time.
5393 while (src <= limit - sizeof(uintptr_t)) {
5394 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
5395 if (AsciiRangeMask(w, lo, hi) != 0) {
5396 changed = true;
5397 break;
5398 }
5399 *reinterpret_cast<uintptr_t*>(dst) = w;
5400 src += sizeof(uintptr_t);
5401 dst += sizeof(uintptr_t);
5402 }
5403 // Process the remainder of the input performing conversion when
5404 // required one word at a time.
5405 while (src <= limit - sizeof(uintptr_t)) {
5406 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
5407 uintptr_t m = AsciiRangeMask(w, lo, hi);
5408 // The mask has high (7th) bit set in every byte that needs
5409 // conversion and we know that the distance between cases is
5410 // 1 << 5.
5411 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
5412 src += sizeof(uintptr_t);
5413 dst += sizeof(uintptr_t);
5414 }
5415#endif
5416 // Process the last few bytes of the input (or the whole input if
5417 // unaligned access is not supported).
5418 while (src < limit) {
5419 char c = *src;
5420 if (lo < c && c < hi) {
5421 c ^= (1 << 5);
5422 changed = true;
5423 }
5424 *dst = c;
5425 ++src;
5426 ++dst;
5427 }
5428#ifdef DEBUG
5429 CheckConvert(saved_dst, saved_src, length, changed);
5430#endif
5431 return changed;
5432 }
5433
5434#ifdef DEBUG
5435 static void CheckConvert(char* dst, char* src, int length, bool changed) {
5436 bool expected_changed = false;
5437 for (int i = 0; i < length; i++) {
5438 if (dst[i] == src[i]) continue;
5439 expected_changed = true;
5440 if (dir == ASCII_TO_LOWER) {
5441 ASSERT('A' <= src[i] && src[i] <= 'Z');
5442 ASSERT(dst[i] == src[i] + ('a' - 'A'));
5443 } else {
5444 ASSERT(dir == ASCII_TO_UPPER);
5445 ASSERT('a' <= src[i] && src[i] <= 'z');
5446 ASSERT(dst[i] == src[i] - ('a' - 'A'));
5447 }
5448 }
5449 ASSERT(expected_changed == changed);
5450 }
5451#endif
5452};
5453
5454
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005455struct ToLowerTraits {
5456 typedef unibrow::ToLowercase UnibrowConverter;
5457
lrn@chromium.org303ada72010-10-27 09:33:13 +00005458 typedef FastAsciiConverter<ASCII_TO_LOWER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005459};
5460
5461
5462struct ToUpperTraits {
5463 typedef unibrow::ToUppercase UnibrowConverter;
5464
lrn@chromium.org303ada72010-10-27 09:33:13 +00005465 typedef FastAsciiConverter<ASCII_TO_UPPER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005466};
5467
5468} // namespace
5469
5470
5471template <typename ConvertTraits>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005472MUST_USE_RESULT static MaybeObject* ConvertCase(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005473 Arguments args,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005474 Isolate* isolate,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005475 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005476 NoHandleAllocation ha;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005477 CONVERT_CHECKED(String, s, args[0]);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005478 s = s->TryFlattenGetString();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005479
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005480 const int length = s->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005481 // Assume that the string is not empty; we need this assumption later
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005482 if (length == 0) return s;
5483
5484 // Simpler handling of ascii strings.
5485 //
5486 // NOTE: This assumes that the upper/lower case of an ascii
5487 // character is also ascii. This is currently the case, but it
5488 // might break in the future if we implement more context and locale
5489 // dependent upper/lower conversions.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005490 if (s->IsSeqAsciiString()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005491 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005492 { MaybeObject* maybe_o = isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005493 if (!maybe_o->ToObject(&o)) return maybe_o;
5494 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005495 SeqAsciiString* result = SeqAsciiString::cast(o);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005496 bool has_changed_character = ConvertTraits::AsciiConverter::Convert(
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005497 result->GetChars(), SeqAsciiString::cast(s)->GetChars(), length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005498 return has_changed_character ? result : s;
5499 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005500
lrn@chromium.org303ada72010-10-27 09:33:13 +00005501 Object* answer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005502 { MaybeObject* maybe_answer =
5503 ConvertCaseHelper(isolate, s, length, length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005504 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5505 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005506 if (answer->IsSmi()) {
5507 // Retry with correct length.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005508 { MaybeObject* maybe_answer =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005509 ConvertCaseHelper(isolate,
5510 s, Smi::cast(answer)->value(), length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005511 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5512 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005513 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00005514 return answer;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005515}
5516
5517
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005518RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToLowerCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005519 return ConvertCase<ToLowerTraits>(
5520 args, isolate, isolate->runtime_state()->to_lower_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005521}
5522
5523
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005524RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToUpperCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005525 return ConvertCase<ToUpperTraits>(
5526 args, isolate, isolate->runtime_state()->to_upper_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005527}
5528
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005529
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005530static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
5531 return unibrow::WhiteSpace::Is(c) || c == 0x200b;
5532}
5533
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005534
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005535RUNTIME_FUNCTION(MaybeObject*, Runtime_StringTrim) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005536 NoHandleAllocation ha;
5537 ASSERT(args.length() == 3);
5538
5539 CONVERT_CHECKED(String, s, args[0]);
5540 CONVERT_BOOLEAN_CHECKED(trimLeft, args[1]);
5541 CONVERT_BOOLEAN_CHECKED(trimRight, args[2]);
5542
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005543 s->TryFlatten();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005544 int length = s->length();
5545
5546 int left = 0;
5547 if (trimLeft) {
5548 while (left < length && IsTrimWhiteSpace(s->Get(left))) {
5549 left++;
5550 }
5551 }
5552
5553 int right = length;
5554 if (trimRight) {
5555 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) {
5556 right--;
5557 }
5558 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005559 return s->SubString(left, right);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005560}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005561
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005562
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005563template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005564void FindStringIndices(Isolate* isolate,
5565 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005566 Vector<const PatternChar> pattern,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005567 ZoneList<int>* indices,
5568 unsigned int limit) {
5569 ASSERT(limit > 0);
5570 // Collect indices of pattern in subject, and the end-of-string index.
5571 // Stop after finding at most limit values.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005572 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005573 int pattern_length = pattern.length();
5574 int index = 0;
5575 while (limit > 0) {
5576 index = search.Search(subject, index);
5577 if (index < 0) return;
5578 indices->Add(index);
5579 index += pattern_length;
5580 limit--;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005581 }
5582}
5583
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005584
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005585RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005586 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005587 HandleScope handle_scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005588 CONVERT_ARG_CHECKED(String, subject, 0);
5589 CONVERT_ARG_CHECKED(String, pattern, 1);
5590 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
5591
5592 int subject_length = subject->length();
5593 int pattern_length = pattern->length();
5594 RUNTIME_ASSERT(pattern_length > 0);
5595
5596 // The limit can be very large (0xffffffffu), but since the pattern
5597 // isn't empty, we can never create more parts than ~half the length
5598 // of the subject.
5599
5600 if (!subject->IsFlat()) FlattenString(subject);
5601
5602 static const int kMaxInitialListCapacity = 16;
5603
5604 ZoneScope scope(DELETE_ON_EXIT);
5605
5606 // Find (up to limit) indices of separator and end-of-string in subject
5607 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
5608 ZoneList<int> indices(initial_capacity);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005609 if (!pattern->IsFlat()) FlattenString(pattern);
5610
5611 // No allocation block.
5612 {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005613 AssertNoAllocation nogc;
5614 if (subject->IsAsciiRepresentation()) {
5615 Vector<const char> subject_vector = subject->ToAsciiVector();
5616 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005617 FindStringIndices(isolate,
5618 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005619 pattern->ToAsciiVector(),
5620 &indices,
5621 limit);
5622 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005623 FindStringIndices(isolate,
5624 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005625 pattern->ToUC16Vector(),
5626 &indices,
5627 limit);
5628 }
5629 } else {
5630 Vector<const uc16> subject_vector = subject->ToUC16Vector();
5631 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005632 FindStringIndices(isolate,
5633 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005634 pattern->ToAsciiVector(),
5635 &indices,
5636 limit);
5637 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005638 FindStringIndices(isolate,
5639 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005640 pattern->ToUC16Vector(),
5641 &indices,
5642 limit);
5643 }
5644 }
5645 }
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005646
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005647 if (static_cast<uint32_t>(indices.length()) < limit) {
5648 indices.Add(subject_length);
5649 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005650
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005651 // The list indices now contains the end of each part to create.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005652
5653 // Create JSArray of substrings separated by separator.
5654 int part_count = indices.length();
5655
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005656 Handle<JSArray> result = isolate->factory()->NewJSArray(part_count);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005657 result->set_length(Smi::FromInt(part_count));
5658
5659 ASSERT(result->HasFastElements());
5660
5661 if (part_count == 1 && indices.at(0) == subject_length) {
5662 FixedArray::cast(result->elements())->set(0, *subject);
5663 return *result;
5664 }
5665
5666 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
5667 int part_start = 0;
5668 for (int i = 0; i < part_count; i++) {
5669 HandleScope local_loop_handle;
5670 int part_end = indices.at(i);
5671 Handle<String> substring =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005672 isolate->factory()->NewSubString(subject, part_start, part_end);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005673 elements->set(i, *substring);
5674 part_start = part_end + pattern_length;
5675 }
5676
5677 return *result;
5678}
5679
5680
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005681// Copies ascii characters to the given fixed array looking up
5682// one-char strings in the cache. Gives up on the first char that is
5683// not in the cache and fills the remainder with smi zeros. Returns
5684// the length of the successfully copied prefix.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005685static int CopyCachedAsciiCharsToArray(Heap* heap,
5686 const char* chars,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005687 FixedArray* elements,
5688 int length) {
5689 AssertNoAllocation nogc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005690 FixedArray* ascii_cache = heap->single_character_string_cache();
5691 Object* undefined = heap->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005692 int i;
5693 for (i = 0; i < length; ++i) {
5694 Object* value = ascii_cache->get(chars[i]);
5695 if (value == undefined) break;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005696 ASSERT(!heap->InNewSpace(value));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005697 elements->set(i, value, SKIP_WRITE_BARRIER);
5698 }
5699 if (i < length) {
5700 ASSERT(Smi::FromInt(0) == 0);
5701 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
5702 }
5703#ifdef DEBUG
5704 for (int j = 0; j < length; ++j) {
5705 Object* element = elements->get(j);
5706 ASSERT(element == Smi::FromInt(0) ||
5707 (element->IsString() && String::cast(element)->LooksValid()));
5708 }
5709#endif
5710 return i;
5711}
5712
5713
5714// Converts a String to JSArray.
5715// For example, "foo" => ["f", "o", "o"].
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005716RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToArray) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005717 HandleScope scope(isolate);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005718 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005719 CONVERT_ARG_CHECKED(String, s, 0);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005720 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005721
5722 s->TryFlatten();
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005723 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005724
5725 Handle<FixedArray> elements;
5726 if (s->IsFlat() && s->IsAsciiRepresentation()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005727 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005728 { MaybeObject* maybe_obj =
5729 isolate->heap()->AllocateUninitializedFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005730 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5731 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005732 elements = Handle<FixedArray>(FixedArray::cast(obj), isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005733
5734 Vector<const char> chars = s->ToAsciiVector();
5735 // Note, this will initialize all elements (not only the prefix)
5736 // to prevent GC from seeing partially initialized array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005737 int num_copied_from_cache = CopyCachedAsciiCharsToArray(isolate->heap(),
5738 chars.start(),
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005739 *elements,
5740 length);
5741
5742 for (int i = num_copied_from_cache; i < length; ++i) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00005743 Handle<Object> str = LookupSingleCharacterStringFromCode(chars[i]);
5744 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005745 }
5746 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005747 elements = isolate->factory()->NewFixedArray(length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005748 for (int i = 0; i < length; ++i) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00005749 Handle<Object> str = LookupSingleCharacterStringFromCode(s->Get(i));
5750 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005751 }
5752 }
5753
5754#ifdef DEBUG
5755 for (int i = 0; i < length; ++i) {
5756 ASSERT(String::cast(elements->get(i))->length() == 1);
5757 }
5758#endif
5759
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005760 return *isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005761}
5762
5763
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005764RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStringWrapper) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005765 NoHandleAllocation ha;
5766 ASSERT(args.length() == 1);
5767 CONVERT_CHECKED(String, value, args[0]);
5768 return value->ToObject();
5769}
5770
5771
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005772bool Runtime::IsUpperCaseChar(RuntimeState* runtime_state, uint16_t ch) {
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00005773 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005774 int char_length = runtime_state->to_upper_mapping()->get(ch, 0, chars);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00005775 return char_length == 0;
5776}
5777
5778
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005779RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005780 NoHandleAllocation ha;
5781 ASSERT(args.length() == 1);
5782
5783 Object* number = args[0];
5784 RUNTIME_ASSERT(number->IsNumber());
5785
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005786 return isolate->heap()->NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005787}
5788
5789
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005790RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToStringSkipCache) {
ager@chromium.org357bf652010-04-12 11:30:10 +00005791 NoHandleAllocation ha;
5792 ASSERT(args.length() == 1);
5793
5794 Object* number = args[0];
5795 RUNTIME_ASSERT(number->IsNumber());
5796
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005797 return isolate->heap()->NumberToString(number, false);
ager@chromium.org357bf652010-04-12 11:30:10 +00005798}
5799
5800
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005801RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToInteger) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005802 NoHandleAllocation ha;
5803 ASSERT(args.length() == 1);
5804
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005805 CONVERT_DOUBLE_CHECKED(number, args[0]);
5806
5807 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5808 if (number > 0 && number <= Smi::kMaxValue) {
5809 return Smi::FromInt(static_cast<int>(number));
5810 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005811 return isolate->heap()->NumberFromDouble(DoubleToInteger(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005812}
5813
5814
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005815RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToIntegerMapMinusZero) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005816 NoHandleAllocation ha;
5817 ASSERT(args.length() == 1);
5818
5819 CONVERT_DOUBLE_CHECKED(number, args[0]);
5820
5821 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5822 if (number > 0 && number <= Smi::kMaxValue) {
5823 return Smi::FromInt(static_cast<int>(number));
5824 }
5825
5826 double double_value = DoubleToInteger(number);
5827 // Map both -0 and +0 to +0.
5828 if (double_value == 0) double_value = 0;
5829
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005830 return isolate->heap()->NumberFromDouble(double_value);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005831}
5832
5833
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005834RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSUint32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005835 NoHandleAllocation ha;
5836 ASSERT(args.length() == 1);
5837
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005838 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005839 return isolate->heap()->NumberFromUint32(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005840}
5841
5842
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005843RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSInt32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005844 NoHandleAllocation ha;
5845 ASSERT(args.length() == 1);
5846
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005847 CONVERT_DOUBLE_CHECKED(number, args[0]);
5848
5849 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5850 if (number > 0 && number <= Smi::kMaxValue) {
5851 return Smi::FromInt(static_cast<int>(number));
5852 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005853 return isolate->heap()->NumberFromInt32(DoubleToInt32(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005854}
5855
5856
ager@chromium.org870a0b62008-11-04 11:43:05 +00005857// Converts a Number to a Smi, if possible. Returns NaN if the number is not
5858// a small integer.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005859RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToSmi) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00005860 NoHandleAllocation ha;
5861 ASSERT(args.length() == 1);
5862
5863 Object* obj = args[0];
5864 if (obj->IsSmi()) {
5865 return obj;
5866 }
5867 if (obj->IsHeapNumber()) {
5868 double value = HeapNumber::cast(obj)->value();
5869 int int_value = FastD2I(value);
5870 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
5871 return Smi::FromInt(int_value);
5872 }
5873 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005874 return isolate->heap()->nan_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00005875}
5876
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005877
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005878RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateHeapNumber) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005879 NoHandleAllocation ha;
5880 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005881 return isolate->heap()->AllocateHeapNumber(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005882}
5883
5884
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005885RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005886 NoHandleAllocation ha;
5887 ASSERT(args.length() == 2);
5888
5889 CONVERT_DOUBLE_CHECKED(x, args[0]);
5890 CONVERT_DOUBLE_CHECKED(y, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005891 return isolate->heap()->NumberFromDouble(x + y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005892}
5893
5894
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005895RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSub) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005896 NoHandleAllocation ha;
5897 ASSERT(args.length() == 2);
5898
5899 CONVERT_DOUBLE_CHECKED(x, args[0]);
5900 CONVERT_DOUBLE_CHECKED(y, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005901 return isolate->heap()->NumberFromDouble(x - y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005902}
5903
5904
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005905RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMul) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005906 NoHandleAllocation ha;
5907 ASSERT(args.length() == 2);
5908
5909 CONVERT_DOUBLE_CHECKED(x, args[0]);
5910 CONVERT_DOUBLE_CHECKED(y, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005911 return isolate->heap()->NumberFromDouble(x * y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005912}
5913
5914
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005915RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberUnaryMinus) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005916 NoHandleAllocation ha;
5917 ASSERT(args.length() == 1);
5918
5919 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005920 return isolate->heap()->NumberFromDouble(-x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005921}
5922
5923
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005924RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAlloc) {
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00005925 NoHandleAllocation ha;
5926 ASSERT(args.length() == 0);
5927
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005928 return isolate->heap()->NumberFromDouble(9876543210.0);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00005929}
5930
5931
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005932RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberDiv) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005933 NoHandleAllocation ha;
5934 ASSERT(args.length() == 2);
5935
5936 CONVERT_DOUBLE_CHECKED(x, args[0]);
5937 CONVERT_DOUBLE_CHECKED(y, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005938 return isolate->heap()->NumberFromDouble(x / y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005939}
5940
5941
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005942RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMod) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005943 NoHandleAllocation ha;
5944 ASSERT(args.length() == 2);
5945
5946 CONVERT_DOUBLE_CHECKED(x, args[0]);
5947 CONVERT_DOUBLE_CHECKED(y, args[1]);
5948
ager@chromium.org3811b432009-10-28 14:53:37 +00005949 x = modulo(x, y);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00005950 // NumberFromDouble may return a Smi instead of a Number object
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005951 return isolate->heap()->NumberFromDouble(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005952}
5953
5954
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005955RUNTIME_FUNCTION(MaybeObject*, Runtime_StringAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005956 NoHandleAllocation ha;
5957 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005958 CONVERT_CHECKED(String, str1, args[0]);
5959 CONVERT_CHECKED(String, str2, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005960 isolate->counters()->string_add_runtime()->Increment();
5961 return isolate->heap()->AllocateConsString(str1, str2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005962}
5963
5964
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005965template <typename sinkchar>
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005966static inline void StringBuilderConcatHelper(String* special,
5967 sinkchar* sink,
5968 FixedArray* fixed_array,
5969 int array_length) {
5970 int position = 0;
5971 for (int i = 0; i < array_length; i++) {
5972 Object* element = fixed_array->get(i);
5973 if (element->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005974 // Smi encoding of position and length.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005975 int encoded_slice = Smi::cast(element)->value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005976 int pos;
5977 int len;
5978 if (encoded_slice > 0) {
5979 // Position and length encoded in one smi.
5980 pos = StringBuilderSubstringPosition::decode(encoded_slice);
5981 len = StringBuilderSubstringLength::decode(encoded_slice);
5982 } else {
5983 // Position and length encoded in two smis.
5984 Object* obj = fixed_array->get(++i);
5985 ASSERT(obj->IsSmi());
5986 pos = Smi::cast(obj)->value();
5987 len = -encoded_slice;
5988 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00005989 String::WriteToFlat(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00005990 sink + position,
5991 pos,
5992 pos + len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005993 position += len;
5994 } else {
5995 String* string = String::cast(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005996 int element_length = string->length();
5997 String::WriteToFlat(string, sink + position, 0, element_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005998 position += element_length;
5999 }
6000 }
6001}
6002
6003
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006004RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006005 NoHandleAllocation ha;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006006 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006007 CONVERT_CHECKED(JSArray, array, args[0]);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006008 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006009 isolate->context()->mark_out_of_memory();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006010 return Failure::OutOfMemoryException();
6011 }
6012 int array_length = Smi::cast(args[1])->value();
6013 CONVERT_CHECKED(String, special, args[2]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006014
6015 // This assumption is used by the slice encoding in one or two smis.
6016 ASSERT(Smi::kMaxValue >= String::kMaxLength);
6017
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006018 int special_length = special->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006019 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006020 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006021 }
6022 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006023 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006024 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006025 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006026
6027 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006028 return isolate->heap()->empty_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006029 } else if (array_length == 1) {
6030 Object* first = fixed_array->get(0);
6031 if (first->IsString()) return first;
6032 }
6033
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006034 bool ascii = special->HasOnlyAsciiChars();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006035 int position = 0;
6036 for (int i = 0; i < array_length; i++) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006037 int increment = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006038 Object* elt = fixed_array->get(i);
6039 if (elt->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006040 // Smi encoding of position and length.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006041 int smi_value = Smi::cast(elt)->value();
6042 int pos;
6043 int len;
6044 if (smi_value > 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006045 // Position and length encoded in one smi.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006046 pos = StringBuilderSubstringPosition::decode(smi_value);
6047 len = StringBuilderSubstringLength::decode(smi_value);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006048 } else {
6049 // Position and length encoded in two smis.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006050 len = -smi_value;
6051 // Get the position and check that it is a positive smi.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006052 i++;
6053 if (i >= array_length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006054 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006055 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006056 Object* next_smi = fixed_array->get(i);
6057 if (!next_smi->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006058 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006059 }
6060 pos = Smi::cast(next_smi)->value();
6061 if (pos < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006062 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006063 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006064 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006065 ASSERT(pos >= 0);
6066 ASSERT(len >= 0);
6067 if (pos > special_length || len > special_length - pos) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006068 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006069 }
6070 increment = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006071 } else if (elt->IsString()) {
6072 String* element = String::cast(elt);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006073 int element_length = element->length();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006074 increment = element_length;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006075 if (ascii && !element->HasOnlyAsciiChars()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006076 ascii = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006077 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006078 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006079 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006080 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006081 if (increment > String::kMaxLength - position) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006082 isolate->context()->mark_out_of_memory();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006083 return Failure::OutOfMemoryException();
6084 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006085 position += increment;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006086 }
6087
6088 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006089 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006090
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006091 if (ascii) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006092 { MaybeObject* maybe_object =
6093 isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006094 if (!maybe_object->ToObject(&object)) return maybe_object;
6095 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006096 SeqAsciiString* answer = SeqAsciiString::cast(object);
6097 StringBuilderConcatHelper(special,
6098 answer->GetChars(),
6099 fixed_array,
6100 array_length);
6101 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006102 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006103 { MaybeObject* maybe_object =
6104 isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006105 if (!maybe_object->ToObject(&object)) return maybe_object;
6106 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006107 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6108 StringBuilderConcatHelper(special,
6109 answer->GetChars(),
6110 fixed_array,
6111 array_length);
6112 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006113 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006114}
6115
6116
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006117RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderJoin) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006118 NoHandleAllocation ha;
6119 ASSERT(args.length() == 3);
6120 CONVERT_CHECKED(JSArray, array, args[0]);
6121 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006122 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006123 return Failure::OutOfMemoryException();
6124 }
6125 int array_length = Smi::cast(args[1])->value();
6126 CONVERT_CHECKED(String, separator, args[2]);
6127
6128 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006129 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006130 }
6131 FixedArray* fixed_array = FixedArray::cast(array->elements());
6132 if (fixed_array->length() < array_length) {
6133 array_length = fixed_array->length();
6134 }
6135
6136 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006137 return isolate->heap()->empty_string();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006138 } else if (array_length == 1) {
6139 Object* first = fixed_array->get(0);
6140 if (first->IsString()) return first;
6141 }
6142
6143 int separator_length = separator->length();
6144 int max_nof_separators =
6145 (String::kMaxLength + separator_length - 1) / separator_length;
6146 if (max_nof_separators < (array_length - 1)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006147 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006148 return Failure::OutOfMemoryException();
6149 }
6150 int length = (array_length - 1) * separator_length;
6151 for (int i = 0; i < array_length; i++) {
6152 Object* element_obj = fixed_array->get(i);
6153 if (!element_obj->IsString()) {
6154 // TODO(1161): handle this case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006155 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006156 }
6157 String* element = String::cast(element_obj);
6158 int increment = element->length();
6159 if (increment > String::kMaxLength - length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006160 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006161 return Failure::OutOfMemoryException();
6162 }
6163 length += increment;
6164 }
6165
6166 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006167 { MaybeObject* maybe_object =
6168 isolate->heap()->AllocateRawTwoByteString(length);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006169 if (!maybe_object->ToObject(&object)) return maybe_object;
6170 }
6171 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6172
6173 uc16* sink = answer->GetChars();
6174#ifdef DEBUG
6175 uc16* end = sink + length;
6176#endif
6177
6178 String* first = String::cast(fixed_array->get(0));
6179 int first_length = first->length();
6180 String::WriteToFlat(first, sink, 0, first_length);
6181 sink += first_length;
6182
6183 for (int i = 1; i < array_length; i++) {
6184 ASSERT(sink + separator_length <= end);
6185 String::WriteToFlat(separator, sink, 0, separator_length);
6186 sink += separator_length;
6187
6188 String* element = String::cast(fixed_array->get(i));
6189 int element_length = element->length();
6190 ASSERT(sink + element_length <= end);
6191 String::WriteToFlat(element, sink, 0, element_length);
6192 sink += element_length;
6193 }
6194 ASSERT(sink == end);
6195
6196 ASSERT(!answer->HasOnlyAsciiChars()); // Use %_FastAsciiArrayJoin instead.
6197 return answer;
6198}
6199
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006200template <typename Char>
6201static void JoinSparseArrayWithSeparator(FixedArray* elements,
6202 int elements_length,
6203 uint32_t array_length,
6204 String* separator,
6205 Vector<Char> buffer) {
6206 int previous_separator_position = 0;
6207 int separator_length = separator->length();
6208 int cursor = 0;
6209 for (int i = 0; i < elements_length; i += 2) {
6210 int position = NumberToInt32(elements->get(i));
6211 String* string = String::cast(elements->get(i + 1));
6212 int string_length = string->length();
6213 if (string->length() > 0) {
6214 while (previous_separator_position < position) {
6215 String::WriteToFlat<Char>(separator, &buffer[cursor],
6216 0, separator_length);
6217 cursor += separator_length;
6218 previous_separator_position++;
6219 }
6220 String::WriteToFlat<Char>(string, &buffer[cursor],
6221 0, string_length);
6222 cursor += string->length();
6223 }
6224 }
6225 if (separator_length > 0) {
6226 // Array length must be representable as a signed 32-bit number,
6227 // otherwise the total string length would have been too large.
6228 ASSERT(array_length <= 0x7fffffff); // Is int32_t.
6229 int last_array_index = static_cast<int>(array_length - 1);
6230 while (previous_separator_position < last_array_index) {
6231 String::WriteToFlat<Char>(separator, &buffer[cursor],
6232 0, separator_length);
6233 cursor += separator_length;
6234 previous_separator_position++;
6235 }
6236 }
6237 ASSERT(cursor <= buffer.length());
6238}
6239
6240
6241RUNTIME_FUNCTION(MaybeObject*, Runtime_SparseJoinWithSeparator) {
6242 NoHandleAllocation ha;
6243 ASSERT(args.length() == 3);
6244 CONVERT_CHECKED(JSArray, elements_array, args[0]);
6245 RUNTIME_ASSERT(elements_array->HasFastElements());
6246 CONVERT_NUMBER_CHECKED(uint32_t, array_length, Uint32, args[1]);
6247 CONVERT_CHECKED(String, separator, args[2]);
6248 // elements_array is fast-mode JSarray of alternating positions
6249 // (increasing order) and strings.
6250 // array_length is length of original array (used to add separators);
6251 // separator is string to put between elements. Assumed to be non-empty.
6252
6253 // Find total length of join result.
6254 int string_length = 0;
6255 bool is_ascii = true;
6256 int max_string_length = SeqAsciiString::kMaxLength;
6257 bool overflow = false;
6258 CONVERT_NUMBER_CHECKED(int, elements_length,
6259 Int32, elements_array->length());
6260 RUNTIME_ASSERT((elements_length & 1) == 0); // Even length.
6261 FixedArray* elements = FixedArray::cast(elements_array->elements());
6262 for (int i = 0; i < elements_length; i += 2) {
6263 RUNTIME_ASSERT(elements->get(i)->IsNumber());
6264 CONVERT_CHECKED(String, string, elements->get(i + 1));
6265 int length = string->length();
6266 if (is_ascii && !string->IsAsciiRepresentation()) {
6267 is_ascii = false;
6268 max_string_length = SeqTwoByteString::kMaxLength;
6269 }
6270 if (length > max_string_length ||
6271 max_string_length - length < string_length) {
6272 overflow = true;
6273 break;
6274 }
6275 string_length += length;
6276 }
6277 int separator_length = separator->length();
6278 if (!overflow && separator_length > 0) {
6279 if (array_length <= 0x7fffffffu) {
6280 int separator_count = static_cast<int>(array_length) - 1;
6281 int remaining_length = max_string_length - string_length;
6282 if ((remaining_length / separator_length) >= separator_count) {
6283 string_length += separator_length * (array_length - 1);
6284 } else {
6285 // Not room for the separators within the maximal string length.
6286 overflow = true;
6287 }
6288 } else {
6289 // Nonempty separator and at least 2^31-1 separators necessary
6290 // means that the string is too large to create.
6291 STATIC_ASSERT(String::kMaxLength < 0x7fffffff);
6292 overflow = true;
6293 }
6294 }
6295 if (overflow) {
6296 // Throw OutOfMemory exception for creating too large a string.
6297 V8::FatalProcessOutOfMemory("Array join result too large.");
6298 }
6299
6300 if (is_ascii) {
6301 MaybeObject* result_allocation =
6302 isolate->heap()->AllocateRawAsciiString(string_length);
6303 if (result_allocation->IsFailure()) return result_allocation;
6304 SeqAsciiString* result_string =
6305 SeqAsciiString::cast(result_allocation->ToObjectUnchecked());
6306 JoinSparseArrayWithSeparator<char>(elements,
6307 elements_length,
6308 array_length,
6309 separator,
6310 Vector<char>(result_string->GetChars(),
6311 string_length));
6312 return result_string;
6313 } else {
6314 MaybeObject* result_allocation =
6315 isolate->heap()->AllocateRawTwoByteString(string_length);
6316 if (result_allocation->IsFailure()) return result_allocation;
6317 SeqTwoByteString* result_string =
6318 SeqTwoByteString::cast(result_allocation->ToObjectUnchecked());
6319 JoinSparseArrayWithSeparator<uc16>(elements,
6320 elements_length,
6321 array_length,
6322 separator,
6323 Vector<uc16>(result_string->GetChars(),
6324 string_length));
6325 return result_string;
6326 }
6327}
6328
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006329
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006330RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberOr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006331 NoHandleAllocation ha;
6332 ASSERT(args.length() == 2);
6333
6334 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6335 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006336 return isolate->heap()->NumberFromInt32(x | y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006337}
6338
6339
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006340RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAnd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006341 NoHandleAllocation ha;
6342 ASSERT(args.length() == 2);
6343
6344 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6345 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006346 return isolate->heap()->NumberFromInt32(x & y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006347}
6348
6349
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006350RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberXor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006351 NoHandleAllocation ha;
6352 ASSERT(args.length() == 2);
6353
6354 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6355 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006356 return isolate->heap()->NumberFromInt32(x ^ y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006357}
6358
6359
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006360RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberNot) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006361 NoHandleAllocation ha;
6362 ASSERT(args.length() == 1);
6363
6364 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006365 return isolate->heap()->NumberFromInt32(~x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006366}
6367
6368
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006369RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShl) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006370 NoHandleAllocation ha;
6371 ASSERT(args.length() == 2);
6372
6373 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6374 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006375 return isolate->heap()->NumberFromInt32(x << (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006376}
6377
6378
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006379RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006380 NoHandleAllocation ha;
6381 ASSERT(args.length() == 2);
6382
6383 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
6384 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006385 return isolate->heap()->NumberFromUint32(x >> (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006386}
6387
6388
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006389RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSar) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006390 NoHandleAllocation ha;
6391 ASSERT(args.length() == 2);
6392
6393 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6394 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006395 return isolate->heap()->NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006396}
6397
6398
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006399RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006400 NoHandleAllocation ha;
6401 ASSERT(args.length() == 2);
6402
6403 CONVERT_DOUBLE_CHECKED(x, args[0]);
6404 CONVERT_DOUBLE_CHECKED(y, args[1]);
6405 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
6406 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
6407 if (x == y) return Smi::FromInt(EQUAL);
6408 Object* result;
6409 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
6410 result = Smi::FromInt(EQUAL);
6411 } else {
6412 result = Smi::FromInt(NOT_EQUAL);
6413 }
6414 return result;
6415}
6416
6417
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006418RUNTIME_FUNCTION(MaybeObject*, Runtime_StringEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006419 NoHandleAllocation ha;
6420 ASSERT(args.length() == 2);
6421
6422 CONVERT_CHECKED(String, x, args[0]);
6423 CONVERT_CHECKED(String, y, args[1]);
6424
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006425 bool not_equal = !x->Equals(y);
6426 // This is slightly convoluted because the value that signifies
6427 // equality is 0 and inequality is 1 so we have to negate the result
6428 // from String::Equals.
6429 ASSERT(not_equal == 0 || not_equal == 1);
6430 STATIC_CHECK(EQUAL == 0);
6431 STATIC_CHECK(NOT_EQUAL == 1);
6432 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006433}
6434
6435
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006436RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006437 NoHandleAllocation ha;
6438 ASSERT(args.length() == 3);
6439
6440 CONVERT_DOUBLE_CHECKED(x, args[0]);
6441 CONVERT_DOUBLE_CHECKED(y, args[1]);
6442 if (isnan(x) || isnan(y)) return args[2];
6443 if (x == y) return Smi::FromInt(EQUAL);
6444 if (isless(x, y)) return Smi::FromInt(LESS);
6445 return Smi::FromInt(GREATER);
6446}
6447
6448
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006449// Compare two Smis as if they were converted to strings and then
6450// compared lexicographically.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006451RUNTIME_FUNCTION(MaybeObject*, Runtime_SmiLexicographicCompare) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006452 NoHandleAllocation ha;
6453 ASSERT(args.length() == 2);
6454
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006455 // Extract the integer values from the Smis.
6456 CONVERT_CHECKED(Smi, x, args[0]);
6457 CONVERT_CHECKED(Smi, y, args[1]);
6458 int x_value = x->value();
6459 int y_value = y->value();
6460
6461 // If the integers are equal so are the string representations.
6462 if (x_value == y_value) return Smi::FromInt(EQUAL);
6463
6464 // If one of the integers are zero the normal integer order is the
6465 // same as the lexicographic order of the string representations.
6466 if (x_value == 0 || y_value == 0) return Smi::FromInt(x_value - y_value);
6467
ager@chromium.org32912102009-01-16 10:38:43 +00006468 // If only one of the integers is negative the negative number is
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006469 // smallest because the char code of '-' is less than the char code
6470 // of any digit. Otherwise, we make both values positive.
6471 if (x_value < 0 || y_value < 0) {
6472 if (y_value >= 0) return Smi::FromInt(LESS);
6473 if (x_value >= 0) return Smi::FromInt(GREATER);
6474 x_value = -x_value;
6475 y_value = -y_value;
6476 }
6477
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006478 // Arrays for the individual characters of the two Smis. Smis are
6479 // 31 bit integers and 10 decimal digits are therefore enough.
6480 // TODO(isolates): maybe we should simply allocate 20 bytes on the stack.
6481 int* x_elms = isolate->runtime_state()->smi_lexicographic_compare_x_elms();
6482 int* y_elms = isolate->runtime_state()->smi_lexicographic_compare_y_elms();
6483
6484
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006485 // Convert the integers to arrays of their decimal digits.
6486 int x_index = 0;
6487 int y_index = 0;
6488 while (x_value > 0) {
6489 x_elms[x_index++] = x_value % 10;
6490 x_value /= 10;
6491 }
6492 while (y_value > 0) {
6493 y_elms[y_index++] = y_value % 10;
6494 y_value /= 10;
6495 }
6496
6497 // Loop through the arrays of decimal digits finding the first place
6498 // where they differ.
6499 while (--x_index >= 0 && --y_index >= 0) {
6500 int diff = x_elms[x_index] - y_elms[y_index];
6501 if (diff != 0) return Smi::FromInt(diff);
6502 }
6503
6504 // If one array is a suffix of the other array, the longest array is
6505 // the representation of the largest of the Smis in the
6506 // lexicographic ordering.
6507 return Smi::FromInt(x_index - y_index);
6508}
6509
6510
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006511static Object* StringInputBufferCompare(RuntimeState* state,
6512 String* x,
6513 String* y) {
6514 StringInputBuffer& bufx = *state->string_input_buffer_compare_bufx();
6515 StringInputBuffer& bufy = *state->string_input_buffer_compare_bufy();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006516 bufx.Reset(x);
6517 bufy.Reset(y);
6518 while (bufx.has_more() && bufy.has_more()) {
6519 int d = bufx.GetNext() - bufy.GetNext();
6520 if (d < 0) return Smi::FromInt(LESS);
6521 else if (d > 0) return Smi::FromInt(GREATER);
6522 }
6523
6524 // x is (non-trivial) prefix of y:
6525 if (bufy.has_more()) return Smi::FromInt(LESS);
6526 // y is prefix of x:
6527 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
6528}
6529
6530
6531static Object* FlatStringCompare(String* x, String* y) {
6532 ASSERT(x->IsFlat());
6533 ASSERT(y->IsFlat());
6534 Object* equal_prefix_result = Smi::FromInt(EQUAL);
6535 int prefix_length = x->length();
6536 if (y->length() < prefix_length) {
6537 prefix_length = y->length();
6538 equal_prefix_result = Smi::FromInt(GREATER);
6539 } else if (y->length() > prefix_length) {
6540 equal_prefix_result = Smi::FromInt(LESS);
6541 }
6542 int r;
6543 if (x->IsAsciiRepresentation()) {
6544 Vector<const char> x_chars = x->ToAsciiVector();
6545 if (y->IsAsciiRepresentation()) {
6546 Vector<const char> y_chars = y->ToAsciiVector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006547 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006548 } else {
6549 Vector<const uc16> y_chars = y->ToUC16Vector();
6550 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6551 }
6552 } else {
6553 Vector<const uc16> x_chars = x->ToUC16Vector();
6554 if (y->IsAsciiRepresentation()) {
6555 Vector<const char> y_chars = y->ToAsciiVector();
6556 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6557 } else {
6558 Vector<const uc16> y_chars = y->ToUC16Vector();
6559 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6560 }
6561 }
6562 Object* result;
6563 if (r == 0) {
6564 result = equal_prefix_result;
6565 } else {
6566 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
6567 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006568 ASSERT(result ==
6569 StringInputBufferCompare(Isolate::Current()->runtime_state(), x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006570 return result;
6571}
6572
6573
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006574RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006575 NoHandleAllocation ha;
6576 ASSERT(args.length() == 2);
6577
6578 CONVERT_CHECKED(String, x, args[0]);
6579 CONVERT_CHECKED(String, y, args[1]);
6580
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006581 isolate->counters()->string_compare_runtime()->Increment();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006582
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006583 // A few fast case tests before we flatten.
6584 if (x == y) return Smi::FromInt(EQUAL);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006585 if (y->length() == 0) {
6586 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006587 return Smi::FromInt(GREATER);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006588 } else if (x->length() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006589 return Smi::FromInt(LESS);
6590 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006591
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006592 int d = x->Get(0) - y->Get(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006593 if (d < 0) return Smi::FromInt(LESS);
6594 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006595
lrn@chromium.org303ada72010-10-27 09:33:13 +00006596 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006597 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(x);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006598 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6599 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006600 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(y);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006601 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6602 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006603
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006604 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006605 : StringInputBufferCompare(isolate->runtime_state(), x, y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006606}
6607
6608
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006609RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_acos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006610 NoHandleAllocation ha;
6611 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006612 isolate->counters()->math_acos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006613
6614 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006615 return isolate->transcendental_cache()->Get(TranscendentalCache::ACOS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006616}
6617
6618
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006619RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_asin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006620 NoHandleAllocation ha;
6621 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006622 isolate->counters()->math_asin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006623
6624 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006625 return isolate->transcendental_cache()->Get(TranscendentalCache::ASIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006626}
6627
6628
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006629RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006630 NoHandleAllocation ha;
6631 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006632 isolate->counters()->math_atan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006633
6634 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006635 return isolate->transcendental_cache()->Get(TranscendentalCache::ATAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006636}
6637
6638
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006639static const double kPiDividedBy4 = 0.78539816339744830962;
6640
6641
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006642RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan2) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006643 NoHandleAllocation ha;
6644 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006645 isolate->counters()->math_atan2()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006646
6647 CONVERT_DOUBLE_CHECKED(x, args[0]);
6648 CONVERT_DOUBLE_CHECKED(y, args[1]);
6649 double result;
6650 if (isinf(x) && isinf(y)) {
6651 // Make sure that the result in case of two infinite arguments
6652 // is a multiple of Pi / 4. The sign of the result is determined
6653 // by the first argument (x) and the sign of the second argument
6654 // determines the multiplier: one or three.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006655 int multiplier = (x < 0) ? -1 : 1;
6656 if (y < 0) multiplier *= 3;
6657 result = multiplier * kPiDividedBy4;
6658 } else {
6659 result = atan2(x, y);
6660 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006661 return isolate->heap()->AllocateHeapNumber(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006662}
6663
6664
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006665RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_ceil) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006666 NoHandleAllocation ha;
6667 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006668 isolate->counters()->math_ceil()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006669
6670 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006671 return isolate->heap()->NumberFromDouble(ceiling(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006672}
6673
6674
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006675RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_cos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006676 NoHandleAllocation ha;
6677 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006678 isolate->counters()->math_cos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006679
6680 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006681 return isolate->transcendental_cache()->Get(TranscendentalCache::COS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006682}
6683
6684
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006685RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_exp) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006686 NoHandleAllocation ha;
6687 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006688 isolate->counters()->math_exp()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006689
6690 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006691 return isolate->transcendental_cache()->Get(TranscendentalCache::EXP, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006692}
6693
6694
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006695RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_floor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006696 NoHandleAllocation ha;
6697 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006698 isolate->counters()->math_floor()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006699
6700 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006701 return isolate->heap()->NumberFromDouble(floor(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006702}
6703
6704
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006705RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_log) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006706 NoHandleAllocation ha;
6707 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006708 isolate->counters()->math_log()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006709
6710 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006711 return isolate->transcendental_cache()->Get(TranscendentalCache::LOG, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006712}
6713
6714
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006715RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006716 NoHandleAllocation ha;
6717 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006718 isolate->counters()->math_pow()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006719
6720 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006721
6722 // If the second argument is a smi, it is much faster to call the
6723 // custom powi() function than the generic pow().
6724 if (args[1]->IsSmi()) {
6725 int y = Smi::cast(args[1])->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006726 return isolate->heap()->NumberFromDouble(power_double_int(x, y));
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006727 }
6728
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006729 CONVERT_DOUBLE_CHECKED(y, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006730 return isolate->heap()->AllocateHeapNumber(power_double_double(x, y));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006731}
6732
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006733// Fast version of Math.pow if we know that y is not an integer and
6734// y is not -0.5 or 0.5. Used as slowcase from codegen.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006735RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow_cfunction) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006736 NoHandleAllocation ha;
6737 ASSERT(args.length() == 2);
6738 CONVERT_DOUBLE_CHECKED(x, args[0]);
6739 CONVERT_DOUBLE_CHECKED(y, args[1]);
6740 if (y == 0) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006741 return Smi::FromInt(1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006742 } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006743 return isolate->heap()->nan_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006744 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006745 return isolate->heap()->AllocateHeapNumber(pow(x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006746 }
6747}
6748
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006749
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006750RUNTIME_FUNCTION(MaybeObject*, Runtime_RoundNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006751 NoHandleAllocation ha;
6752 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006753 isolate->counters()->math_round()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006754
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006755 if (!args[0]->IsHeapNumber()) {
6756 // Must be smi. Return the argument unchanged for all the other types
6757 // to make fuzz-natives test happy.
6758 return args[0];
6759 }
6760
6761 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
6762
6763 double value = number->value();
6764 int exponent = number->get_exponent();
6765 int sign = number->get_sign();
6766
danno@chromium.org160a7b02011-04-18 15:51:38 +00006767 if (exponent < -1) {
6768 // Number in range ]-0.5..0.5[. These always round to +/-zero.
6769 if (sign) return isolate->heap()->minus_zero_value();
6770 return Smi::FromInt(0);
6771 }
6772
6773 // We compare with kSmiValueSize - 2 because (2^30 - 0.1) has exponent 29 and
6774 // should be rounded to 2^30, which is not smi (for 31-bit smis, similar
6775 // agument holds for 32-bit smis).
6776 if (!sign && exponent < kSmiValueSize - 2) {
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006777 return Smi::FromInt(static_cast<int>(value + 0.5));
6778 }
6779
6780 // If the magnitude is big enough, there's no place for fraction part. If we
6781 // try to add 0.5 to this number, 1.0 will be added instead.
6782 if (exponent >= 52) {
6783 return number;
6784 }
6785
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006786 if (sign && value >= -0.5) return isolate->heap()->minus_zero_value();
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006787
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006788 // Do not call NumberFromDouble() to avoid extra checks.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006789 return isolate->heap()->AllocateHeapNumber(floor(value + 0.5));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006790}
6791
6792
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006793RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006794 NoHandleAllocation ha;
6795 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006796 isolate->counters()->math_sin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006797
6798 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006799 return isolate->transcendental_cache()->Get(TranscendentalCache::SIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006800}
6801
6802
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006803RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sqrt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006804 NoHandleAllocation ha;
6805 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006806 isolate->counters()->math_sqrt()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006807
6808 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006809 return isolate->heap()->AllocateHeapNumber(sqrt(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006810}
6811
6812
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006813RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_tan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006814 NoHandleAllocation ha;
6815 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006816 isolate->counters()->math_tan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006817
6818 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006819 return isolate->transcendental_cache()->Get(TranscendentalCache::TAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006820}
6821
6822
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006823static int MakeDay(int year, int month, int day) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006824 static const int day_from_month[] = {0, 31, 59, 90, 120, 151,
6825 181, 212, 243, 273, 304, 334};
6826 static const int day_from_month_leap[] = {0, 31, 60, 91, 121, 152,
6827 182, 213, 244, 274, 305, 335};
6828
6829 year += month / 12;
6830 month %= 12;
6831 if (month < 0) {
6832 year--;
6833 month += 12;
6834 }
6835
6836 ASSERT(month >= 0);
6837 ASSERT(month < 12);
6838
6839 // year_delta is an arbitrary number such that:
6840 // a) year_delta = -1 (mod 400)
6841 // b) year + year_delta > 0 for years in the range defined by
6842 // ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of
6843 // Jan 1 1970. This is required so that we don't run into integer
6844 // division of negative numbers.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006845 // c) there shouldn't be an overflow for 32-bit integers in the following
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006846 // operations.
6847 static const int year_delta = 399999;
6848 static const int base_day = 365 * (1970 + year_delta) +
6849 (1970 + year_delta) / 4 -
6850 (1970 + year_delta) / 100 +
6851 (1970 + year_delta) / 400;
6852
6853 int year1 = year + year_delta;
6854 int day_from_year = 365 * year1 +
6855 year1 / 4 -
6856 year1 / 100 +
6857 year1 / 400 -
6858 base_day;
6859
6860 if (year % 4 || (year % 100 == 0 && year % 400 != 0)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006861 return day_from_year + day_from_month[month] + day - 1;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006862 }
6863
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006864 return day_from_year + day_from_month_leap[month] + day - 1;
6865}
6866
6867
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006868RUNTIME_FUNCTION(MaybeObject*, Runtime_DateMakeDay) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006869 NoHandleAllocation ha;
6870 ASSERT(args.length() == 3);
6871
6872 CONVERT_SMI_CHECKED(year, args[0]);
6873 CONVERT_SMI_CHECKED(month, args[1]);
6874 CONVERT_SMI_CHECKED(date, args[2]);
6875
6876 return Smi::FromInt(MakeDay(year, month, date));
6877}
6878
6879
6880static const int kDays4Years[] = {0, 365, 2 * 365, 3 * 365 + 1};
6881static const int kDaysIn4Years = 4 * 365 + 1;
6882static const int kDaysIn100Years = 25 * kDaysIn4Years - 1;
6883static const int kDaysIn400Years = 4 * kDaysIn100Years + 1;
6884static const int kDays1970to2000 = 30 * 365 + 7;
6885static const int kDaysOffset = 1000 * kDaysIn400Years + 5 * kDaysIn400Years -
6886 kDays1970to2000;
6887static const int kYearsOffset = 400000;
6888
6889static const char kDayInYear[] = {
6890 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6891 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6892 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6893 22, 23, 24, 25, 26, 27, 28,
6894 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6895 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6896 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6897 22, 23, 24, 25, 26, 27, 28, 29, 30,
6898 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6899 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6900 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6901 22, 23, 24, 25, 26, 27, 28, 29, 30,
6902 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6903 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6904 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6905 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6906 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6907 22, 23, 24, 25, 26, 27, 28, 29, 30,
6908 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6909 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6910 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6911 22, 23, 24, 25, 26, 27, 28, 29, 30,
6912 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6913 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6914
6915 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6916 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6917 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6918 22, 23, 24, 25, 26, 27, 28,
6919 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6920 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6921 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6922 22, 23, 24, 25, 26, 27, 28, 29, 30,
6923 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6924 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6925 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6926 22, 23, 24, 25, 26, 27, 28, 29, 30,
6927 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6928 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6929 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6930 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6931 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6932 22, 23, 24, 25, 26, 27, 28, 29, 30,
6933 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6934 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6935 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6936 22, 23, 24, 25, 26, 27, 28, 29, 30,
6937 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6938 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6939
6940 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6941 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6942 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6943 22, 23, 24, 25, 26, 27, 28, 29,
6944 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6945 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6946 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6947 22, 23, 24, 25, 26, 27, 28, 29, 30,
6948 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6949 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6950 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6951 22, 23, 24, 25, 26, 27, 28, 29, 30,
6952 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6953 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6954 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6955 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6956 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6957 22, 23, 24, 25, 26, 27, 28, 29, 30,
6958 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6959 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6960 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6961 22, 23, 24, 25, 26, 27, 28, 29, 30,
6962 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6963 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6964
6965 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6966 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6967 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6968 22, 23, 24, 25, 26, 27, 28,
6969 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6970 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6971 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6972 22, 23, 24, 25, 26, 27, 28, 29, 30,
6973 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6974 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6975 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6976 22, 23, 24, 25, 26, 27, 28, 29, 30,
6977 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6978 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6979 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6980 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6981 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6982 22, 23, 24, 25, 26, 27, 28, 29, 30,
6983 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6984 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6985 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6986 22, 23, 24, 25, 26, 27, 28, 29, 30,
6987 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6988 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
6989
6990static const char kMonthInYear[] = {
6991 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,
6992 0, 0, 0, 0, 0, 0,
6993 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,
6994 1, 1, 1,
6995 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,
6996 2, 2, 2, 2, 2, 2,
6997 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,
6998 3, 3, 3, 3, 3,
6999 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,
7000 4, 4, 4, 4, 4, 4,
7001 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,
7002 5, 5, 5, 5, 5,
7003 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,
7004 6, 6, 6, 6, 6, 6,
7005 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,
7006 7, 7, 7, 7, 7, 7,
7007 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,
7008 8, 8, 8, 8, 8,
7009 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,
7010 9, 9, 9, 9, 9, 9,
7011 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7012 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7013 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7014 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7015
7016 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,
7017 0, 0, 0, 0, 0, 0,
7018 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,
7019 1, 1, 1,
7020 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,
7021 2, 2, 2, 2, 2, 2,
7022 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,
7023 3, 3, 3, 3, 3,
7024 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,
7025 4, 4, 4, 4, 4, 4,
7026 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,
7027 5, 5, 5, 5, 5,
7028 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,
7029 6, 6, 6, 6, 6, 6,
7030 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,
7031 7, 7, 7, 7, 7, 7,
7032 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,
7033 8, 8, 8, 8, 8,
7034 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,
7035 9, 9, 9, 9, 9, 9,
7036 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7037 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7038 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7039 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7040
7041 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,
7042 0, 0, 0, 0, 0, 0,
7043 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,
7044 1, 1, 1, 1,
7045 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,
7046 2, 2, 2, 2, 2, 2,
7047 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,
7048 3, 3, 3, 3, 3,
7049 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,
7050 4, 4, 4, 4, 4, 4,
7051 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,
7052 5, 5, 5, 5, 5,
7053 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,
7054 6, 6, 6, 6, 6, 6,
7055 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,
7056 7, 7, 7, 7, 7, 7,
7057 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,
7058 8, 8, 8, 8, 8,
7059 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,
7060 9, 9, 9, 9, 9, 9,
7061 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7062 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7063 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7064 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7065
7066 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,
7067 0, 0, 0, 0, 0, 0,
7068 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,
7069 1, 1, 1,
7070 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,
7071 2, 2, 2, 2, 2, 2,
7072 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,
7073 3, 3, 3, 3, 3,
7074 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,
7075 4, 4, 4, 4, 4, 4,
7076 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,
7077 5, 5, 5, 5, 5,
7078 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,
7079 6, 6, 6, 6, 6, 6,
7080 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,
7081 7, 7, 7, 7, 7, 7,
7082 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,
7083 8, 8, 8, 8, 8,
7084 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,
7085 9, 9, 9, 9, 9, 9,
7086 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7087 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7088 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7089 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11};
7090
7091
7092// This function works for dates from 1970 to 2099.
7093static inline void DateYMDFromTimeAfter1970(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007094 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007095#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007096 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007097#endif
7098
7099 year = 1970 + (4 * date + 2) / kDaysIn4Years;
7100 date %= kDaysIn4Years;
7101
7102 month = kMonthInYear[date];
7103 day = kDayInYear[date];
7104
7105 ASSERT(MakeDay(year, month, day) == save_date);
7106}
7107
7108
7109static inline void DateYMDFromTimeSlow(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007110 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007111#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007112 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007113#endif
7114
7115 date += kDaysOffset;
7116 year = 400 * (date / kDaysIn400Years) - kYearsOffset;
7117 date %= kDaysIn400Years;
7118
7119 ASSERT(MakeDay(year, 0, 1) + date == save_date);
7120
7121 date--;
7122 int yd1 = date / kDaysIn100Years;
7123 date %= kDaysIn100Years;
7124 year += 100 * yd1;
7125
7126 date++;
7127 int yd2 = date / kDaysIn4Years;
7128 date %= kDaysIn4Years;
7129 year += 4 * yd2;
7130
7131 date--;
7132 int yd3 = date / 365;
7133 date %= 365;
7134 year += yd3;
7135
7136 bool is_leap = (!yd1 || yd2) && !yd3;
7137
7138 ASSERT(date >= -1);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007139 ASSERT(is_leap || (date >= 0));
7140 ASSERT((date < 365) || (is_leap && (date < 366)));
7141 ASSERT(is_leap == ((year % 4 == 0) && (year % 100 || (year % 400 == 0))));
7142 ASSERT(is_leap || ((MakeDay(year, 0, 1) + date) == save_date));
7143 ASSERT(!is_leap || ((MakeDay(year, 0, 1) + date + 1) == save_date));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007144
7145 if (is_leap) {
7146 day = kDayInYear[2*365 + 1 + date];
7147 month = kMonthInYear[2*365 + 1 + date];
7148 } else {
7149 day = kDayInYear[date];
7150 month = kMonthInYear[date];
7151 }
7152
7153 ASSERT(MakeDay(year, month, day) == save_date);
7154}
7155
7156
7157static inline void DateYMDFromTime(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007158 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007159 if (date >= 0 && date < 32 * kDaysIn4Years) {
7160 DateYMDFromTimeAfter1970(date, year, month, day);
7161 } else {
7162 DateYMDFromTimeSlow(date, year, month, day);
7163 }
7164}
7165
7166
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007167RUNTIME_FUNCTION(MaybeObject*, Runtime_DateYMDFromTime) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007168 NoHandleAllocation ha;
7169 ASSERT(args.length() == 2);
7170
7171 CONVERT_DOUBLE_CHECKED(t, args[0]);
7172 CONVERT_CHECKED(JSArray, res_array, args[1]);
7173
7174 int year, month, day;
7175 DateYMDFromTime(static_cast<int>(floor(t / 86400000)), year, month, day);
7176
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007177 RUNTIME_ASSERT(res_array->elements()->map() ==
7178 isolate->heap()->fixed_array_map());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00007179 FixedArray* elms = FixedArray::cast(res_array->elements());
7180 RUNTIME_ASSERT(elms->length() == 3);
7181
7182 elms->set(0, Smi::FromInt(year));
7183 elms->set(1, Smi::FromInt(month));
7184 elms->set(2, Smi::FromInt(day));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007185
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007186 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007187}
7188
7189
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007190RUNTIME_FUNCTION(MaybeObject*, Runtime_NewArgumentsFast) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007191 NoHandleAllocation ha;
7192 ASSERT(args.length() == 3);
7193
7194 JSFunction* callee = JSFunction::cast(args[0]);
7195 Object** parameters = reinterpret_cast<Object**>(args[1]);
7196 const int length = Smi::cast(args[2])->value();
7197
lrn@chromium.org303ada72010-10-27 09:33:13 +00007198 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007199 { MaybeObject* maybe_result =
7200 isolate->heap()->AllocateArgumentsObject(callee, length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007201 if (!maybe_result->ToObject(&result)) return maybe_result;
7202 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007203 // Allocate the elements if needed.
7204 if (length > 0) {
7205 // Allocate the fixed array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007206 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007207 { MaybeObject* maybe_obj = isolate->heap()->AllocateRawFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007208 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7209 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007210
7211 AssertNoAllocation no_gc;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007212 FixedArray* array = reinterpret_cast<FixedArray*>(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007213 array->set_map(isolate->heap()->fixed_array_map());
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007214 array->set_length(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007215
7216 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007217 for (int i = 0; i < length; i++) {
7218 array->set(i, *--parameters, mode);
7219 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007220 JSObject::cast(result)->set_elements(FixedArray::cast(obj));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007221 }
7222 return result;
7223}
7224
7225
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007226RUNTIME_FUNCTION(MaybeObject*, Runtime_NewClosure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007227 HandleScope scope(isolate);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007228 ASSERT(args.length() == 3);
ager@chromium.org3811b432009-10-28 14:53:37 +00007229 CONVERT_ARG_CHECKED(Context, context, 0);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007230 CONVERT_ARG_CHECKED(SharedFunctionInfo, shared, 1);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007231 CONVERT_BOOLEAN_CHECKED(pretenure, args[2]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007232
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007233 // Allocate global closures in old space and allocate local closures
7234 // in new space. Additionally pretenure closures that are assigned
7235 // directly to properties.
7236 pretenure = pretenure || (context->global_context() == *context);
7237 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007238 Handle<JSFunction> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007239 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
7240 context,
7241 pretenure_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007242 return *result;
7243}
7244
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007245
7246static SmartPointer<Object**> GetNonBoundArguments(int bound_argc,
7247 int* total_argc) {
7248 // Find frame containing arguments passed to the caller.
7249 JavaScriptFrameIterator it;
7250 JavaScriptFrame* frame = it.frame();
7251 List<JSFunction*> functions(2);
7252 frame->GetFunctions(&functions);
7253 if (functions.length() > 1) {
7254 int inlined_frame_index = functions.length() - 1;
7255 JSFunction* inlined_function = functions[inlined_frame_index];
7256 int args_count = inlined_function->shared()->formal_parameter_count();
7257 ScopedVector<SlotRef> args_slots(args_count);
7258 SlotRef::ComputeSlotMappingForArguments(frame,
7259 inlined_frame_index,
7260 &args_slots);
7261
7262 *total_argc = bound_argc + args_count;
7263 SmartPointer<Object**> param_data(NewArray<Object**>(*total_argc));
7264 for (int i = 0; i < args_count; i++) {
7265 Handle<Object> val = args_slots[i].GetValue();
7266 param_data[bound_argc + i] = val.location();
7267 }
7268 return param_data;
7269 } else {
7270 it.AdvanceToArgumentsFrame();
7271 frame = it.frame();
7272 int args_count = frame->ComputeParametersCount();
7273
7274 *total_argc = bound_argc + args_count;
7275 SmartPointer<Object**> param_data(NewArray<Object**>(*total_argc));
7276 for (int i = 0; i < args_count; i++) {
7277 Handle<Object> val = Handle<Object>(frame->GetParameter(i));
7278 param_data[bound_argc + i] = val.location();
7279 }
7280 return param_data;
7281 }
7282}
7283
7284
7285RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObjectFromBound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007286 HandleScope scope(isolate);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007287 ASSERT(args.length() == 2);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007288 // First argument is a function to use as a constructor.
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007289 CONVERT_ARG_CHECKED(JSFunction, function, 0);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007290
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007291 // Second argument is either null or an array of bound arguments.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007292 Handle<FixedArray> bound_args;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007293 int bound_argc = 0;
7294 if (!args[1]->IsNull()) {
7295 CONVERT_ARG_CHECKED(JSArray, params, 1);
7296 RUNTIME_ASSERT(params->HasFastElements());
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007297 bound_args = Handle<FixedArray>(FixedArray::cast(params->elements()));
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007298 bound_argc = Smi::cast(params->length())->value();
7299 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007300
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007301 int total_argc = 0;
7302 SmartPointer<Object**> param_data =
7303 GetNonBoundArguments(bound_argc, &total_argc);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007304 for (int i = 0; i < bound_argc; i++) {
7305 Handle<Object> val = Handle<Object>(bound_args->get(i));
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007306 param_data[i] = val.location();
7307 }
7308
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007309 bool exception = false;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007310 Handle<Object> result =
7311 Execution::New(function, total_argc, *param_data, &exception);
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007312 if (exception) {
7313 return Failure::Exception();
7314 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007315
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007316 ASSERT(!result.is_null());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007317 return *result;
7318}
7319
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007320
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007321static void TrySettingInlineConstructStub(Isolate* isolate,
7322 Handle<JSFunction> function) {
7323 Handle<Object> prototype = isolate->factory()->null_value();
ager@chromium.org5c838252010-02-19 08:53:10 +00007324 if (function->has_instance_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007325 prototype = Handle<Object>(function->instance_prototype(), isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00007326 }
7327 if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007328 ConstructStubCompiler compiler;
ager@chromium.orgbeb25712010-11-29 08:02:25 +00007329 MaybeObject* code = compiler.CompileConstructStub(*function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007330 if (!code->IsFailure()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007331 function->shared()->set_construct_stub(
7332 Code::cast(code->ToObjectUnchecked()));
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007333 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007334 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007335}
7336
7337
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007338RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007339 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007340 ASSERT(args.length() == 1);
7341
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007342 Handle<Object> constructor = args.at<Object>(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007343
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007344 // If the constructor isn't a proper function we throw a type error.
7345 if (!constructor->IsJSFunction()) {
7346 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
7347 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007348 isolate->factory()->NewTypeError("not_constructor", arguments);
7349 return isolate->Throw(*type_error);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007350 }
7351
7352 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007353
7354 // If function should not have prototype, construction is not allowed. In this
7355 // case generated code bailouts here, since function has no initial_map.
7356 if (!function->should_have_prototype()) {
7357 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
7358 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007359 isolate->factory()->NewTypeError("not_constructor", arguments);
7360 return isolate->Throw(*type_error);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007361 }
7362
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007363#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007364 Debug* debug = isolate->debug();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007365 // Handle stepping into constructors if step into is active.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007366 if (debug->StepInActive()) {
7367 debug->HandleStepIn(function, Handle<Object>::null(), 0, true);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007368 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007369#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007370
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007371 if (function->has_initial_map()) {
7372 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007373 // The 'Function' function ignores the receiver object when
7374 // called using 'new' and creates a new JSFunction object that
7375 // is returned. The receiver object is only used for error
7376 // reporting if an error occurs when constructing the new
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007377 // JSFunction. FACTORY->NewJSObject() should not be used to
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007378 // allocate JSFunctions since it does not properly initialize
7379 // the shared part of the function. Since the receiver is
7380 // ignored anyway, we use the global object as the receiver
7381 // instead of a new JSFunction object. This way, errors are
7382 // reported the same way whether or not 'Function' is called
7383 // using 'new'.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007384 return isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007385 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007386 }
7387
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007388 // The function should be compiled for the optimization hints to be
7389 // available. We cannot use EnsureCompiled because that forces a
7390 // compilation through the shared function info which makes it
7391 // impossible for us to optimize.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007392 Handle<SharedFunctionInfo> shared(function->shared(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007393 if (!function->is_compiled()) CompileLazy(function, CLEAR_EXCEPTION);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007394
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007395 if (!function->has_initial_map() &&
7396 shared->IsInobjectSlackTrackingInProgress()) {
7397 // The tracking is already in progress for another function. We can only
7398 // track one initial_map at a time, so we force the completion before the
7399 // function is called as a constructor for the first time.
7400 shared->CompleteInobjectSlackTracking();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007401 }
7402
7403 bool first_allocation = !shared->live_objects_may_exist();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007404 Handle<JSObject> result = isolate->factory()->NewJSObject(function);
7405 RETURN_IF_EMPTY_HANDLE(isolate, result);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007406 // Delay setting the stub if inobject slack tracking is in progress.
7407 if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007408 TrySettingInlineConstructStub(isolate, function);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007409 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007410
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007411 isolate->counters()->constructed_objects()->Increment();
7412 isolate->counters()->constructed_objects_runtime()->Increment();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007413
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007414 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007415}
7416
7417
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007418RUNTIME_FUNCTION(MaybeObject*, Runtime_FinalizeInstanceSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007419 HandleScope scope(isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007420 ASSERT(args.length() == 1);
7421
7422 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7423 function->shared()->CompleteInobjectSlackTracking();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007424 TrySettingInlineConstructStub(isolate, function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007425
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007426 return isolate->heap()->undefined_value();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007427}
7428
7429
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007430RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007431 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007432 ASSERT(args.length() == 1);
7433
7434 Handle<JSFunction> function = args.at<JSFunction>(0);
7435#ifdef DEBUG
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00007436 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007437 PrintF("[lazy: ");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007438 function->PrintName();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007439 PrintF("]\n");
7440 }
7441#endif
7442
kasperl@chromium.org71affb52009-05-26 05:44:31 +00007443 // Compile the target function. Here we compile using CompileLazyInLoop in
7444 // order to get the optimized version. This helps code like delta-blue
7445 // that calls performance-critical routines through constructors. A
7446 // constructor call doesn't use a CallIC, it uses a LoadIC followed by a
7447 // direct call. Since the in-loop tracking takes place through CallICs
7448 // this means that things called through constructors are never known to
7449 // be in loops. We compile them as if they are in loops here just in case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007450 ASSERT(!function->is_compiled());
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007451 if (!CompileLazyInLoop(function, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007452 return Failure::Exception();
7453 }
7454
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007455 // All done. Return the compiled code.
7456 ASSERT(function->is_compiled());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007457 return function->code();
7458}
7459
7460
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007461RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyRecompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007462 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007463 ASSERT(args.length() == 1);
7464 Handle<JSFunction> function = args.at<JSFunction>(0);
7465 // If the function is not optimizable or debugger is active continue using the
7466 // code from the full compiler.
7467 if (!function->shared()->code()->optimizable() ||
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007468 isolate->DebuggerHasBreakPoints()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007469 if (FLAG_trace_opt) {
7470 PrintF("[failed to optimize ");
7471 function->PrintName();
7472 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n",
7473 function->shared()->code()->optimizable() ? "T" : "F",
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007474 isolate->DebuggerHasBreakPoints() ? "T" : "F");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007475 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007476 function->ReplaceCode(function->shared()->code());
7477 return function->code();
7478 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007479 if (CompileOptimized(function, AstNode::kNoNumber, CLEAR_EXCEPTION)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007480 return function->code();
7481 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007482 if (FLAG_trace_opt) {
7483 PrintF("[failed to optimize ");
7484 function->PrintName();
7485 PrintF(": optimized compilation failed]\n");
7486 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007487 function->ReplaceCode(function->shared()->code());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007488 return function->code();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007489}
7490
7491
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007492RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007493 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007494 ASSERT(args.length() == 1);
7495 RUNTIME_ASSERT(args[0]->IsSmi());
7496 Deoptimizer::BailoutType type =
7497 static_cast<Deoptimizer::BailoutType>(Smi::cast(args[0])->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007498 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
7499 ASSERT(isolate->heap()->IsAllocationAllowed());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007500 int frames = deoptimizer->output_count();
7501
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00007502 deoptimizer->MaterializeHeapNumbers();
7503 delete deoptimizer;
7504
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007505 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007506 JavaScriptFrame* frame = NULL;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00007507 for (int i = 0; i < frames - 1; i++) it.Advance();
7508 frame = it.frame();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007509
7510 RUNTIME_ASSERT(frame->function()->IsJSFunction());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007511 Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007512 Handle<Object> arguments;
7513 for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007514 if (frame->GetExpression(i) == isolate->heap()->arguments_marker()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007515 if (arguments.is_null()) {
7516 // FunctionGetArguments can't throw an exception, so cast away the
7517 // doubt with an assert.
7518 arguments = Handle<Object>(
7519 Accessors::FunctionGetArguments(*function,
7520 NULL)->ToObjectUnchecked());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007521 ASSERT(*arguments != isolate->heap()->null_value());
7522 ASSERT(*arguments != isolate->heap()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007523 }
7524 frame->SetExpression(i, *arguments);
7525 }
7526 }
7527
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007528 isolate->compilation_cache()->MarkForLazyOptimizing(function);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007529 if (type == Deoptimizer::EAGER) {
7530 RUNTIME_ASSERT(function->IsOptimized());
7531 } else {
7532 RUNTIME_ASSERT(!function->IsOptimized());
7533 }
7534
7535 // Avoid doing too much work when running with --always-opt and keep
7536 // the optimized code around.
7537 if (FLAG_always_opt || type == Deoptimizer::LAZY) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007538 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007539 }
7540
7541 // Count the number of optimized activations of the function.
7542 int activations = 0;
7543 while (!it.done()) {
7544 JavaScriptFrame* frame = it.frame();
7545 if (frame->is_optimized() && frame->function() == *function) {
7546 activations++;
7547 }
7548 it.Advance();
7549 }
7550
7551 // TODO(kasperl): For now, we cannot support removing the optimized
7552 // code when we have recursive invocations of the same function.
7553 if (activations == 0) {
7554 if (FLAG_trace_deopt) {
7555 PrintF("[removing optimized code for: ");
7556 function->PrintName();
7557 PrintF("]\n");
7558 }
7559 function->ReplaceCode(function->shared()->code());
7560 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007561 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007562}
7563
7564
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007565RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyOSR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007566 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007567 delete deoptimizer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007568 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007569}
7570
7571
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007572RUNTIME_FUNCTION(MaybeObject*, Runtime_DeoptimizeFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007573 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007574 ASSERT(args.length() == 1);
7575 CONVERT_ARG_CHECKED(JSFunction, function, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007576 if (!function->IsOptimized()) return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007577
7578 Deoptimizer::DeoptimizeFunction(*function);
7579
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007580 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007581}
7582
7583
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00007584RUNTIME_FUNCTION(MaybeObject*, Runtime_OptimizeFunctionOnNextCall) {
7585 HandleScope scope(isolate);
7586 ASSERT(args.length() == 1);
7587 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7588 if (!function->IsOptimizable()) return isolate->heap()->undefined_value();
7589 function->MarkForLazyRecompilation();
7590 return isolate->heap()->undefined_value();
7591}
7592
7593
lrn@chromium.org1c092762011-05-09 09:42:16 +00007594RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationStatus) {
7595 HandleScope scope(isolate);
7596 ASSERT(args.length() == 1);
7597 if (!V8::UseCrankshaft()) {
7598 return Smi::FromInt(4); // 4 == "never".
7599 }
7600 if (FLAG_always_opt) {
7601 return Smi::FromInt(3); // 3 == "always".
7602 }
7603 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7604 return function->IsOptimized() ? Smi::FromInt(1) // 1 == "yes".
7605 : Smi::FromInt(2); // 2 == "no".
7606}
7607
7608
7609RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationCount) {
7610 HandleScope scope(isolate);
7611 ASSERT(args.length() == 1);
7612 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7613 return Smi::FromInt(function->shared()->opt_count());
7614}
7615
7616
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007617RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007618 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007619 ASSERT(args.length() == 1);
7620 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7621
7622 // We're not prepared to handle a function with arguments object.
7623 ASSERT(!function->shared()->scope_info()->HasArgumentsShadow());
7624
7625 // We have hit a back edge in an unoptimized frame for a function that was
7626 // selected for on-stack replacement. Find the unoptimized code object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007627 Handle<Code> unoptimized(function->shared()->code(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007628 // Keep track of whether we've succeeded in optimizing.
7629 bool succeeded = unoptimized->optimizable();
7630 if (succeeded) {
7631 // If we are trying to do OSR when there are already optimized
7632 // activations of the function, it means (a) the function is directly or
7633 // indirectly recursive and (b) an optimized invocation has been
7634 // deoptimized so that we are currently in an unoptimized activation.
7635 // Check for optimized activations of this function.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007636 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007637 while (succeeded && !it.done()) {
7638 JavaScriptFrame* frame = it.frame();
7639 succeeded = !frame->is_optimized() || frame->function() != *function;
7640 it.Advance();
7641 }
7642 }
7643
7644 int ast_id = AstNode::kNoNumber;
7645 if (succeeded) {
7646 // The top JS function is this one, the PC is somewhere in the
7647 // unoptimized code.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007648 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007649 JavaScriptFrame* frame = it.frame();
7650 ASSERT(frame->function() == *function);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007651 ASSERT(frame->LookupCode() == *unoptimized);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007652 ASSERT(unoptimized->contains(frame->pc()));
7653
7654 // Use linear search of the unoptimized code's stack check table to find
7655 // the AST id matching the PC.
7656 Address start = unoptimized->instruction_start();
7657 unsigned target_pc_offset = static_cast<unsigned>(frame->pc() - start);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007658 Address table_cursor = start + unoptimized->stack_check_table_offset();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007659 uint32_t table_length = Memory::uint32_at(table_cursor);
7660 table_cursor += kIntSize;
7661 for (unsigned i = 0; i < table_length; ++i) {
7662 // Table entries are (AST id, pc offset) pairs.
7663 uint32_t pc_offset = Memory::uint32_at(table_cursor + kIntSize);
7664 if (pc_offset == target_pc_offset) {
7665 ast_id = static_cast<int>(Memory::uint32_at(table_cursor));
7666 break;
7667 }
7668 table_cursor += 2 * kIntSize;
7669 }
7670 ASSERT(ast_id != AstNode::kNoNumber);
7671 if (FLAG_trace_osr) {
7672 PrintF("[replacing on-stack at AST id %d in ", ast_id);
7673 function->PrintName();
7674 PrintF("]\n");
7675 }
7676
7677 // Try to compile the optimized code. A true return value from
7678 // CompileOptimized means that compilation succeeded, not necessarily
7679 // that optimization succeeded.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007680 if (CompileOptimized(function, ast_id, CLEAR_EXCEPTION) &&
7681 function->IsOptimized()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007682 DeoptimizationInputData* data = DeoptimizationInputData::cast(
7683 function->code()->deoptimization_data());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007684 if (data->OsrPcOffset()->value() >= 0) {
7685 if (FLAG_trace_osr) {
7686 PrintF("[on-stack replacement offset %d in optimized code]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007687 data->OsrPcOffset()->value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007688 }
7689 ASSERT(data->OsrAstId()->value() == ast_id);
7690 } else {
7691 // We may never generate the desired OSR entry if we emit an
7692 // early deoptimize.
7693 succeeded = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007694 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007695 } else {
7696 succeeded = false;
7697 }
7698 }
7699
7700 // Revert to the original stack checks in the original unoptimized code.
7701 if (FLAG_trace_osr) {
7702 PrintF("[restoring original stack checks in ");
7703 function->PrintName();
7704 PrintF("]\n");
7705 }
7706 StackCheckStub check_stub;
7707 Handle<Code> check_code = check_stub.GetCode();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00007708 Handle<Code> replacement_code = isolate->builtins()->OnStackReplacement();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007709 Deoptimizer::RevertStackCheckCode(*unoptimized,
7710 *check_code,
7711 *replacement_code);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007712
7713 // Allow OSR only at nesting level zero again.
7714 unoptimized->set_allow_osr_at_loop_nesting_level(0);
7715
7716 // If the optimization attempt succeeded, return the AST id tagged as a
7717 // smi. This tells the builtin that we need to translate the unoptimized
7718 // frame to an optimized one.
7719 if (succeeded) {
7720 ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
7721 return Smi::FromInt(ast_id);
7722 } else {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007723 if (function->IsMarkedForLazyRecompilation()) {
7724 function->ReplaceCode(function->shared()->code());
7725 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007726 return Smi::FromInt(-1);
7727 }
7728}
7729
7730
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007731RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007732 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007733 ASSERT(args.length() == 1);
7734 RUNTIME_ASSERT(!args[0]->IsJSFunction());
7735 return *Execution::GetFunctionDelegate(args.at<Object>(0));
7736}
7737
7738
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007739RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructorDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007740 HandleScope scope(isolate);
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00007741 ASSERT(args.length() == 1);
7742 RUNTIME_ASSERT(!args[0]->IsJSFunction());
7743 return *Execution::GetConstructorDelegate(args.at<Object>(0));
7744}
7745
7746
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007747RUNTIME_FUNCTION(MaybeObject*, Runtime_NewContext) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007748 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00007749 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007750
kasper.lund7276f142008-07-30 08:49:36 +00007751 CONVERT_CHECKED(JSFunction, function, args[0]);
ager@chromium.orgb5737492010-07-15 09:29:43 +00007752 int length = function->shared()->scope_info()->NumberOfContextSlots();
lrn@chromium.org303ada72010-10-27 09:33:13 +00007753 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007754 { MaybeObject* maybe_result =
7755 isolate->heap()->AllocateFunctionContext(length, function);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007756 if (!maybe_result->ToObject(&result)) return maybe_result;
7757 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007758
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007759 isolate->set_context(Context::cast(result));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007760
kasper.lund7276f142008-07-30 08:49:36 +00007761 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007762}
7763
lrn@chromium.org303ada72010-10-27 09:33:13 +00007764
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007765MUST_USE_RESULT static MaybeObject* PushContextHelper(Isolate* isolate,
7766 Object* object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00007767 bool is_catch_context) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007768 // Convert the object to a proper JavaScript object.
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007769 Object* js_object = object;
7770 if (!js_object->IsJSObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007771 MaybeObject* maybe_js_object = js_object->ToObject();
7772 if (!maybe_js_object->ToObject(&js_object)) {
7773 if (!Failure::cast(maybe_js_object)->IsInternalError()) {
7774 return maybe_js_object;
7775 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007776 HandleScope scope(isolate);
7777 Handle<Object> handle(object, isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007778 Handle<Object> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007779 isolate->factory()->NewTypeError("with_expression",
7780 HandleVector(&handle, 1));
7781 return isolate->Throw(*result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007782 }
7783 }
7784
lrn@chromium.org303ada72010-10-27 09:33:13 +00007785 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007786 { MaybeObject* maybe_result = isolate->heap()->AllocateWithContext(
7787 isolate->context(), JSObject::cast(js_object), is_catch_context);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007788 if (!maybe_result->ToObject(&result)) return maybe_result;
7789 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007790
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007791 Context* context = Context::cast(result);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007792 isolate->set_context(context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007793
kasper.lund7276f142008-07-30 08:49:36 +00007794 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007795}
7796
7797
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007798RUNTIME_FUNCTION(MaybeObject*, Runtime_PushContext) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007799 NoHandleAllocation ha;
7800 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007801 return PushContextHelper(isolate, args[0], false);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007802}
7803
7804
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007805RUNTIME_FUNCTION(MaybeObject*, Runtime_PushCatchContext) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007806 NoHandleAllocation ha;
7807 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007808 return PushContextHelper(isolate, args[0], true);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007809}
7810
7811
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007812RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007813 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007814 ASSERT(args.length() == 2);
7815
7816 CONVERT_ARG_CHECKED(Context, context, 0);
7817 CONVERT_ARG_CHECKED(String, name, 1);
7818
7819 int index;
7820 PropertyAttributes attributes;
7821 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007822 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007823
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007824 // If the slot was not found the result is true.
7825 if (holder.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007826 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007827 }
7828
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007829 // If the slot was found in a context, it should be DONT_DELETE.
7830 if (holder->IsContext()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007831 return isolate->heap()->false_value();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007832 }
7833
7834 // The slot was found in a JSObject, either a context extension object,
7835 // the global object, or an arguments object. Try to delete it
7836 // (respecting DONT_DELETE). For consistency with V8's usual behavior,
7837 // which allows deleting all parameters in functions that mention
7838 // 'arguments', we do this even for the case of slots found on an
7839 // arguments object. The slot was found on an arguments object if the
7840 // index is non-negative.
7841 Handle<JSObject> object = Handle<JSObject>::cast(holder);
7842 if (index >= 0) {
7843 return object->DeleteElement(index, JSObject::NORMAL_DELETION);
7844 } else {
7845 return object->DeleteProperty(*name, JSObject::NORMAL_DELETION);
7846 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007847}
7848
7849
ager@chromium.orga1645e22009-09-09 19:27:10 +00007850// A mechanism to return a pair of Object pointers in registers (if possible).
7851// How this is achieved is calling convention-dependent.
7852// All currently supported x86 compiles uses calling conventions that are cdecl
7853// variants where a 64-bit value is returned in two 32-bit registers
7854// (edx:eax on ia32, r1:r0 on ARM).
7855// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
7856// In Win64 calling convention, a struct of two pointers is returned in memory,
7857// allocated by the caller, and passed as a pointer in a hidden first parameter.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007858#ifdef V8_HOST_ARCH_64_BIT
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007859struct ObjectPair {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007860 MaybeObject* x;
7861 MaybeObject* y;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007862};
ager@chromium.orga1645e22009-09-09 19:27:10 +00007863
lrn@chromium.org303ada72010-10-27 09:33:13 +00007864static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007865 ObjectPair result = {x, y};
ager@chromium.orga1645e22009-09-09 19:27:10 +00007866 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
7867 // In Win64 they are assigned to a hidden first argument.
7868 return result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007869}
7870#else
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007871typedef uint64_t ObjectPair;
lrn@chromium.org303ada72010-10-27 09:33:13 +00007872static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007873 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007874 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007875}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007876#endif
7877
7878
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007879static inline MaybeObject* Unhole(Heap* heap,
7880 MaybeObject* x,
lrn@chromium.org303ada72010-10-27 09:33:13 +00007881 PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007882 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
7883 USE(attributes);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007884 return x->IsTheHole() ? heap->undefined_value() : x;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007885}
7886
7887
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007888static JSObject* ComputeReceiverForNonGlobal(Isolate* isolate,
7889 JSObject* holder) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007890 ASSERT(!holder->IsGlobalObject());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007891 Context* top = isolate->context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007892 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007893 JSFunction* context_extension_function =
7894 top->global_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007895 // If the holder isn't a context extension object, we just return it
7896 // as the receiver. This allows arguments objects to be used as
7897 // receivers, but only if they are put in the context scope chain
7898 // explicitly via a with-statement.
7899 Object* constructor = holder->map()->constructor();
7900 if (constructor != context_extension_function) return holder;
7901 // Fall back to using the global object as the receiver if the
7902 // property turns out to be a local variable allocated in a context
7903 // extension object - introduced via eval.
7904 return top->global()->global_receiver();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007905}
7906
7907
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007908static ObjectPair LoadContextSlotHelper(Arguments args,
7909 Isolate* isolate,
7910 bool throw_error) {
7911 HandleScope scope(isolate);
ager@chromium.orga1645e22009-09-09 19:27:10 +00007912 ASSERT_EQ(2, args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007913
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007914 if (!args[0]->IsContext() || !args[1]->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007915 return MakePair(isolate->ThrowIllegalOperation(), NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007916 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007917 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007918 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007919
7920 int index;
7921 PropertyAttributes attributes;
7922 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007923 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007924
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007925 // If the index is non-negative, the slot has been found in a local
7926 // variable or a parameter. Read it from the context object or the
7927 // arguments object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007928 if (index >= 0) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007929 // If the "property" we were looking for is a local variable or an
7930 // argument in a context, the receiver is the global object; see
7931 // ECMA-262, 3rd., 10.1.6 and 10.2.3.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00007932 // GetElement below can cause GC.
7933 Handle<JSObject> receiver(
7934 isolate->context()->global()->global_receiver());
lrn@chromium.org303ada72010-10-27 09:33:13 +00007935 MaybeObject* value = (holder->IsContext())
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007936 ? Context::cast(*holder)->get(index)
7937 : JSObject::cast(*holder)->GetElement(index);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00007938 return MakePair(Unhole(isolate->heap(), value, attributes), *receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007939 }
7940
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007941 // If the holder is found, we read the property from it.
7942 if (!holder.is_null() && holder->IsJSObject()) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007943 ASSERT(Handle<JSObject>::cast(holder)->HasProperty(*name));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007944 JSObject* object = JSObject::cast(*holder);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007945 JSObject* receiver;
7946 if (object->IsGlobalObject()) {
7947 receiver = GlobalObject::cast(object)->global_receiver();
7948 } else if (context->is_exception_holder(*holder)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007949 receiver = isolate->context()->global()->global_receiver();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007950 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007951 receiver = ComputeReceiverForNonGlobal(isolate, object);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007952 }
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00007953
7954 // GetProperty below can cause GC.
7955 Handle<JSObject> receiver_handle(receiver);
7956
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007957 // No need to unhole the value here. This is taken care of by the
7958 // GetProperty function.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007959 MaybeObject* value = object->GetProperty(*name);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00007960 return MakePair(value, *receiver_handle);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007961 }
7962
7963 if (throw_error) {
7964 // The property doesn't exist - throw exception.
7965 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007966 isolate->factory()->NewReferenceError("not_defined",
7967 HandleVector(&name, 1));
7968 return MakePair(isolate->Throw(*reference_error), NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007969 } else {
7970 // The property doesn't exist - return undefined
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007971 return MakePair(isolate->heap()->undefined_value(),
7972 isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007973 }
7974}
7975
7976
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007977RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007978 return LoadContextSlotHelper(args, isolate, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007979}
7980
7981
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007982RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlotNoReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007983 return LoadContextSlotHelper(args, isolate, false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007984}
7985
7986
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007987RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007988 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00007989 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007990
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007991 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007992 CONVERT_ARG_CHECKED(Context, context, 1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007993 CONVERT_ARG_CHECKED(String, name, 2);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00007994 CONVERT_SMI_CHECKED(strict_unchecked, args[3]);
7995 RUNTIME_ASSERT(strict_unchecked == kStrictMode ||
7996 strict_unchecked == kNonStrictMode);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00007997 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(strict_unchecked);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007998
7999 int index;
8000 PropertyAttributes attributes;
8001 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008002 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008003
8004 if (index >= 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008005 if (holder->IsContext()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008006 // Ignore if read_only variable.
8007 if ((attributes & READ_ONLY) == 0) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008008 // Context is a fixed array and set cannot fail.
8009 Context::cast(*holder)->set(index, *value);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008010 } else if (strict_mode == kStrictMode) {
8011 // Setting read only property in strict mode.
8012 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008013 isolate->factory()->NewTypeError("strict_cannot_assign",
8014 HandleVector(&name, 1));
8015 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008016 }
8017 } else {
8018 ASSERT((attributes & READ_ONLY) == 0);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008019 Handle<Object> result =
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008020 SetElement(Handle<JSObject>::cast(holder), index, value, strict_mode);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008021 if (result.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008022 ASSERT(isolate->has_pending_exception());
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008023 return Failure::Exception();
8024 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008025 }
8026 return *value;
8027 }
8028
8029 // Slow case: The property is not in a FixedArray context.
8030 // It is either in an JSObject extension context or it was not found.
8031 Handle<JSObject> context_ext;
8032
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008033 if (!holder.is_null()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008034 // The property exists in the extension context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008035 context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008036 } else {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008037 // The property was not found.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008038 ASSERT(attributes == ABSENT);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008039
8040 if (strict_mode == kStrictMode) {
8041 // Throw in strict mode (assignment to undefined variable).
8042 Handle<Object> error =
8043 isolate->factory()->NewReferenceError(
8044 "not_defined", HandleVector(&name, 1));
8045 return isolate->Throw(*error);
8046 }
8047 // In non-strict mode, the property is stored in the global context.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008048 attributes = NONE;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008049 context_ext = Handle<JSObject>(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008050 }
8051
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008052 // Set the property, but ignore if read_only variable on the context
8053 // extension object itself.
8054 if ((attributes & READ_ONLY) == 0 ||
8055 (context_ext->GetLocalPropertyAttribute(*name) == ABSENT)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008056 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008057 isolate,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008058 SetProperty(context_ext, name, value, NONE, strict_mode));
8059 } else if (strict_mode == kStrictMode && (attributes & READ_ONLY) != 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008060 // Setting read only property in strict mode.
8061 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008062 isolate->factory()->NewTypeError(
8063 "strict_cannot_assign", HandleVector(&name, 1));
8064 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008065 }
8066 return *value;
8067}
8068
8069
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008070RUNTIME_FUNCTION(MaybeObject*, Runtime_Throw) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008071 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008072 ASSERT(args.length() == 1);
8073
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008074 return isolate->Throw(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008075}
8076
8077
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008078RUNTIME_FUNCTION(MaybeObject*, Runtime_ReThrow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008079 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008080 ASSERT(args.length() == 1);
8081
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008082 return isolate->ReThrow(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008083}
8084
8085
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008086RUNTIME_FUNCTION(MaybeObject*, Runtime_PromoteScheduledException) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008087 ASSERT_EQ(0, args.length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008088 return isolate->PromoteScheduledException();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008089}
8090
8091
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008092RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008093 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008094 ASSERT(args.length() == 1);
8095
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008096 Handle<Object> name(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008097 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008098 isolate->factory()->NewReferenceError("not_defined",
8099 HandleVector(&name, 1));
8100 return isolate->Throw(*reference_error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008101}
8102
8103
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008104RUNTIME_FUNCTION(MaybeObject*, Runtime_StackGuard) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00008105 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008106
8107 // First check if this is a real stack overflow.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008108 if (isolate->stack_guard()->IsStackOverflow()) {
8109 NoHandleAllocation na;
8110 return isolate->StackOverflow();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008111 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008112
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008113 return Execution::HandleStackGuardInterrupt();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008114}
8115
8116
8117// NOTE: These PrintXXX functions are defined for all builds (not just
8118// DEBUG builds) because we may want to be able to trace function
8119// calls in all modes.
8120static void PrintString(String* str) {
8121 // not uncommon to have empty strings
8122 if (str->length() > 0) {
8123 SmartPointer<char> s =
8124 str->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
8125 PrintF("%s", *s);
8126 }
8127}
8128
8129
8130static void PrintObject(Object* obj) {
8131 if (obj->IsSmi()) {
8132 PrintF("%d", Smi::cast(obj)->value());
8133 } else if (obj->IsString() || obj->IsSymbol()) {
8134 PrintString(String::cast(obj));
8135 } else if (obj->IsNumber()) {
8136 PrintF("%g", obj->Number());
8137 } else if (obj->IsFailure()) {
8138 PrintF("<failure>");
8139 } else if (obj->IsUndefined()) {
8140 PrintF("<undefined>");
8141 } else if (obj->IsNull()) {
8142 PrintF("<null>");
8143 } else if (obj->IsTrue()) {
8144 PrintF("<true>");
8145 } else if (obj->IsFalse()) {
8146 PrintF("<false>");
8147 } else {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00008148 PrintF("%p", reinterpret_cast<void*>(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008149 }
8150}
8151
8152
8153static int StackSize() {
8154 int n = 0;
8155 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
8156 return n;
8157}
8158
8159
8160static void PrintTransition(Object* result) {
8161 // indentation
8162 { const int nmax = 80;
8163 int n = StackSize();
8164 if (n <= nmax)
8165 PrintF("%4d:%*s", n, n, "");
8166 else
8167 PrintF("%4d:%*s", n, nmax, "...");
8168 }
8169
8170 if (result == NULL) {
8171 // constructor calls
8172 JavaScriptFrameIterator it;
8173 JavaScriptFrame* frame = it.frame();
8174 if (frame->IsConstructor()) PrintF("new ");
8175 // function name
8176 Object* fun = frame->function();
8177 if (fun->IsJSFunction()) {
8178 PrintObject(JSFunction::cast(fun)->shared()->name());
8179 } else {
8180 PrintObject(fun);
8181 }
8182 // function arguments
8183 // (we are intentionally only printing the actually
8184 // supplied parameters, not all parameters required)
8185 PrintF("(this=");
8186 PrintObject(frame->receiver());
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00008187 const int length = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008188 for (int i = 0; i < length; i++) {
8189 PrintF(", ");
8190 PrintObject(frame->GetParameter(i));
8191 }
8192 PrintF(") {\n");
8193
8194 } else {
8195 // function result
8196 PrintF("} -> ");
8197 PrintObject(result);
8198 PrintF("\n");
8199 }
8200}
8201
8202
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008203RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceEnter) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008204 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008205 NoHandleAllocation ha;
8206 PrintTransition(NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008207 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008208}
8209
8210
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008211RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceExit) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008212 NoHandleAllocation ha;
8213 PrintTransition(args[0]);
8214 return args[0]; // return TOS
8215}
8216
8217
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008218RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008219 NoHandleAllocation ha;
8220 ASSERT(args.length() == 1);
8221
8222#ifdef DEBUG
8223 if (args[0]->IsString()) {
8224 // If we have a string, assume it's a code "marker"
8225 // and print some interesting cpu debugging info.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008226 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008227 JavaScriptFrame* frame = it.frame();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008228 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
8229 frame->fp(), frame->sp(), frame->caller_sp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008230 } else {
8231 PrintF("DebugPrint: ");
8232 }
8233 args[0]->Print();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008234 if (args[0]->IsHeapObject()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008235 PrintF("\n");
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008236 HeapObject::cast(args[0])->map()->Print();
8237 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008238#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008239 // ShortPrint is available in release mode. Print is not.
8240 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008241#endif
8242 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00008243 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008244
8245 return args[0]; // return TOS
8246}
8247
8248
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008249RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugTrace) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008250 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008251 NoHandleAllocation ha;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008252 isolate->PrintStack();
8253 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008254}
8255
8256
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008257RUNTIME_FUNCTION(MaybeObject*, Runtime_DateCurrentTime) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008258 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00008259 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008260
8261 // According to ECMA-262, section 15.9.1, page 117, the precision of
8262 // the number in a Date object representing a particular instant in
8263 // time is milliseconds. Therefore, we floor the result of getting
8264 // the OS time.
8265 double millis = floor(OS::TimeCurrentMillis());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008266 return isolate->heap()->NumberFromDouble(millis);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008267}
8268
8269
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008270RUNTIME_FUNCTION(MaybeObject*, Runtime_DateParseString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008271 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008272 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008273
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008274 CONVERT_ARG_CHECKED(String, str, 0);
8275 FlattenString(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008276
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008277 CONVERT_ARG_CHECKED(JSArray, output, 1);
8278 RUNTIME_ASSERT(output->HasFastElements());
8279
8280 AssertNoAllocation no_allocation;
8281
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008282 FixedArray* output_array = FixedArray::cast(output->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008283 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
8284 bool result;
ager@chromium.org5ec48922009-05-05 07:25:34 +00008285 if (str->IsAsciiRepresentation()) {
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008286 result = DateParser::Parse(str->ToAsciiVector(),
8287 output_array,
8288 isolate->unicode_cache());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008289 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00008290 ASSERT(str->IsTwoByteRepresentation());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008291 result = DateParser::Parse(str->ToUC16Vector(),
8292 output_array,
8293 isolate->unicode_cache());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008294 }
8295
8296 if (result) {
8297 return *output;
8298 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008299 return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008300 }
8301}
8302
8303
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008304RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimezone) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008305 NoHandleAllocation ha;
8306 ASSERT(args.length() == 1);
8307
8308 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00008309 const char* zone = OS::LocalTimezone(x);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008310 return isolate->heap()->AllocateStringFromUtf8(CStrVector(zone));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008311}
8312
8313
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008314RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimeOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008315 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00008316 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008317
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008318 return isolate->heap()->NumberFromDouble(OS::LocalTimeOffset());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008319}
8320
8321
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008322RUNTIME_FUNCTION(MaybeObject*, Runtime_DateDaylightSavingsOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008323 NoHandleAllocation ha;
8324 ASSERT(args.length() == 1);
8325
8326 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008327 return isolate->heap()->NumberFromDouble(OS::DaylightSavingsOffset(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008328}
8329
8330
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008331RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalReceiver) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008332 ASSERT(args.length() == 1);
8333 Object* global = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008334 if (!global->IsJSGlobalObject()) return isolate->heap()->null_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008335 return JSGlobalObject::cast(global)->global_receiver();
8336}
8337
8338
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008339RUNTIME_FUNCTION(MaybeObject*, Runtime_ParseJson) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008340 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008341 ASSERT_EQ(1, args.length());
8342 CONVERT_ARG_CHECKED(String, source, 0);
8343
8344 Handle<Object> result = JsonParser::Parse(source);
8345 if (result.is_null()) {
8346 // Syntax error or stack overflow in scanner.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008347 ASSERT(isolate->has_pending_exception());
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008348 return Failure::Exception();
8349 }
8350 return *result;
8351}
8352
8353
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008354bool CodeGenerationFromStringsAllowed(Isolate* isolate,
8355 Handle<Context> context) {
8356 if (context->allow_code_gen_from_strings()->IsFalse()) {
8357 // Check with callback if set.
8358 AllowCodeGenerationFromStringsCallback callback =
8359 isolate->allow_code_gen_callback();
8360 if (callback == NULL) {
8361 // No callback set and code generation disallowed.
8362 return false;
8363 } else {
8364 // Callback set. Let it decide if code generation is allowed.
8365 VMState state(isolate, EXTERNAL);
8366 return callback(v8::Utils::ToLocal(context));
8367 }
8368 }
8369 return true;
8370}
8371
8372
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008373RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008374 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008375 ASSERT_EQ(1, args.length());
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00008376 CONVERT_ARG_CHECKED(String, source, 0);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008377
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008378 // Extract global context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008379 Handle<Context> context(isolate->context()->global_context());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008380
8381 // Check if global context allows code generation from
8382 // strings. Throw an exception if it doesn't.
8383 if (!CodeGenerationFromStringsAllowed(isolate, context)) {
8384 return isolate->Throw(*isolate->factory()->NewError(
8385 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
8386 }
8387
8388 // Compile source string in the global context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00008389 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(source,
8390 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008391 true,
8392 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00008393 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008394 Handle<JSFunction> fun =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008395 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
8396 context,
8397 NOT_TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008398 return *fun;
8399}
8400
8401
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008402static ObjectPair CompileGlobalEval(Isolate* isolate,
8403 Handle<String> source,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008404 Handle<Object> receiver,
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00008405 StrictModeFlag strict_mode) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008406 Handle<Context> context = Handle<Context>(isolate->context());
8407 Handle<Context> global_context = Handle<Context>(context->global_context());
8408
8409 // Check if global context allows code generation from
8410 // strings. Throw an exception if it doesn't.
8411 if (!CodeGenerationFromStringsAllowed(isolate, global_context)) {
8412 isolate->Throw(*isolate->factory()->NewError(
8413 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
8414 return MakePair(Failure::Exception(), NULL);
8415 }
8416
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008417 // Deal with a normal eval call with a string argument. Compile it
8418 // and return the compiled function bound in the local context.
8419 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
8420 source,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008421 Handle<Context>(isolate->context()),
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008422 context->IsGlobalContext(),
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00008423 strict_mode);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008424 if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008425 Handle<JSFunction> compiled =
8426 isolate->factory()->NewFunctionFromSharedFunctionInfo(
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008427 shared, context, NOT_TENURED);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008428 return MakePair(*compiled, *receiver);
8429}
8430
8431
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008432RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008433 ASSERT(args.length() == 4);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008434
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008435 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008436 Handle<Object> callee = args.at<Object>(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008437 Handle<Object> receiver; // Will be overwritten.
8438
8439 // Compute the calling context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008440 Handle<Context> context = Handle<Context>(isolate->context(), isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008441#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008442 // Make sure Isolate::context() agrees with the old code that traversed
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008443 // the stack frames to compute the context.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008444 StackFrameLocator locator;
8445 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008446 ASSERT(Context::cast(frame->context()) == *context);
8447#endif
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008448
8449 // Find where the 'eval' symbol is bound. It is unaliased only if
8450 // it is bound in the global context.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008451 int index = -1;
8452 PropertyAttributes attributes = ABSENT;
8453 while (true) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008454 receiver = context->Lookup(isolate->factory()->eval_symbol(),
8455 FOLLOW_PROTOTYPE_CHAIN,
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008456 &index, &attributes);
iposva@chromium.org245aa852009-02-10 00:49:54 +00008457 // Stop search when eval is found or when the global context is
8458 // reached.
8459 if (attributes != ABSENT || context->IsGlobalContext()) break;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008460 if (context->is_function_context()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008461 context = Handle<Context>(Context::cast(context->closure()->context()),
8462 isolate);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008463 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008464 context = Handle<Context>(context->previous(), isolate);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008465 }
8466 }
8467
iposva@chromium.org245aa852009-02-10 00:49:54 +00008468 // If eval could not be resolved, it has been deleted and we need to
8469 // throw a reference error.
8470 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008471 Handle<Object> name = isolate->factory()->eval_symbol();
iposva@chromium.org245aa852009-02-10 00:49:54 +00008472 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008473 isolate->factory()->NewReferenceError("not_defined",
8474 HandleVector(&name, 1));
8475 return MakePair(isolate->Throw(*reference_error), NULL);
iposva@chromium.org245aa852009-02-10 00:49:54 +00008476 }
8477
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008478 if (!context->IsGlobalContext()) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008479 // 'eval' is not bound in the global context. Just call the function
8480 // with the given arguments. This is not necessarily the global eval.
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00008481 if (receiver->IsContext() || receiver->IsJSContextExtensionObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008482 receiver = Handle<JSObject>(
8483 isolate->context()->global()->global_receiver(), isolate);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008484 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008485 return MakePair(*callee, *receiver);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008486 }
8487
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008488 // 'eval' is bound in the global context, but it may have been overwritten.
8489 // Compare it to the builtin 'GlobalEval' function to make sure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008490 if (*callee != isolate->global_context()->global_eval_fun() ||
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008491 !args[1]->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008492 return MakePair(*callee,
8493 isolate->context()->global()->global_receiver());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008494 }
8495
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008496 ASSERT(args[3]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008497 return CompileGlobalEval(isolate,
8498 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008499 args.at<Object>(2),
8500 static_cast<StrictModeFlag>(
8501 Smi::cast(args[3])->value()));
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008502}
8503
8504
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008505RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEvalNoLookup) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008506 ASSERT(args.length() == 4);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008507
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008508 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008509 Handle<Object> callee = args.at<Object>(0);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008510
8511 // 'eval' is bound in the global context, but it may have been overwritten.
8512 // Compare it to the builtin 'GlobalEval' function to make sure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008513 if (*callee != isolate->global_context()->global_eval_fun() ||
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008514 !args[1]->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008515 return MakePair(*callee,
8516 isolate->context()->global()->global_receiver());
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008517 }
8518
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008519 ASSERT(args[3]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008520 return CompileGlobalEval(isolate,
8521 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008522 args.at<Object>(2),
8523 static_cast<StrictModeFlag>(
8524 Smi::cast(args[3])->value()));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008525}
8526
8527
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008528RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNewFunctionAttributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008529 // This utility adjusts the property attributes for newly created Function
8530 // object ("new Function(...)") by changing the map.
8531 // All it does is changing the prototype property to enumerable
8532 // as specified in ECMA262, 15.3.5.2.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008533 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008534 ASSERT(args.length() == 1);
8535 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008536
8537 Handle<Map> map = func->shared()->strict_mode()
8538 ? isolate->strict_mode_function_instance_map()
8539 : isolate->function_instance_map();
8540
8541 ASSERT(func->map()->instance_type() == map->instance_type());
8542 ASSERT(func->map()->instance_size() == map->instance_size());
8543 func->set_map(*map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008544 return *func;
8545}
8546
8547
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008548RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateInNewSpace) {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008549 // Allocate a block of memory in NewSpace (filled with a filler).
8550 // Use as fallback for allocation in generated code when NewSpace
8551 // is full.
8552 ASSERT(args.length() == 1);
8553 CONVERT_ARG_CHECKED(Smi, size_smi, 0);
8554 int size = size_smi->value();
8555 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
8556 RUNTIME_ASSERT(size > 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008557 Heap* heap = isolate->heap();
8558 const int kMinFreeNewSpaceAfterGC = heap->InitialSemiSpaceSize() * 3/4;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008559 RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008560 Object* allocation;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008561 { MaybeObject* maybe_allocation = heap->new_space()->AllocateRaw(size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008562 if (maybe_allocation->ToObject(&allocation)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008563 heap->CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008564 }
8565 return maybe_allocation;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008566 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008567}
8568
8569
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008570// Push an object unto an array of objects if it is not already in the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008571// array. Returns true if the element was pushed on the stack and
8572// false otherwise.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008573RUNTIME_FUNCTION(MaybeObject*, Runtime_PushIfAbsent) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008574 ASSERT(args.length() == 2);
8575 CONVERT_CHECKED(JSArray, array, args[0]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008576 CONVERT_CHECKED(JSObject, element, args[1]);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008577 RUNTIME_ASSERT(array->HasFastElements());
8578 int length = Smi::cast(array->length())->value();
8579 FixedArray* elements = FixedArray::cast(array->elements());
8580 for (int i = 0; i < length; i++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008581 if (elements->get(i) == element) return isolate->heap()->false_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008582 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00008583 Object* obj;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008584 // Strict not needed. Used for cycle detection in Array join implementation.
8585 { MaybeObject* maybe_obj = array->SetFastElement(length, element,
8586 kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008587 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8588 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008589 return isolate->heap()->true_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008590}
8591
8592
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008593/**
8594 * A simple visitor visits every element of Array's.
8595 * The backend storage can be a fixed array for fast elements case,
8596 * or a dictionary for sparse array. Since Dictionary is a subtype
8597 * of FixedArray, the class can be used by both fast and slow cases.
8598 * The second parameter of the constructor, fast_elements, specifies
8599 * whether the storage is a FixedArray or Dictionary.
8600 *
8601 * An index limit is used to deal with the situation that a result array
8602 * length overflows 32-bit non-negative integer.
8603 */
8604class ArrayConcatVisitor {
8605 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008606 ArrayConcatVisitor(Isolate* isolate,
8607 Handle<FixedArray> storage,
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008608 bool fast_elements) :
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008609 isolate_(isolate),
8610 storage_(Handle<FixedArray>::cast(
8611 isolate->global_handles()->Create(*storage))),
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008612 index_offset_(0u),
8613 fast_elements_(fast_elements) { }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008614
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008615 ~ArrayConcatVisitor() {
8616 clear_storage();
8617 }
8618
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008619 void visit(uint32_t i, Handle<Object> elm) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008620 if (i >= JSObject::kMaxElementCount - index_offset_) return;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008621 uint32_t index = index_offset_ + i;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008622
8623 if (fast_elements_) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008624 if (index < static_cast<uint32_t>(storage_->length())) {
8625 storage_->set(index, *elm);
8626 return;
8627 }
8628 // Our initial estimate of length was foiled, possibly by
8629 // getters on the arrays increasing the length of later arrays
8630 // during iteration.
8631 // This shouldn't happen in anything but pathological cases.
8632 SetDictionaryMode(index);
8633 // Fall-through to dictionary mode.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008634 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008635 ASSERT(!fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008636 Handle<NumberDictionary> dict(NumberDictionary::cast(*storage_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008637 Handle<NumberDictionary> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008638 isolate_->factory()->DictionaryAtNumberPut(dict, index, elm);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008639 if (!result.is_identical_to(dict)) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008640 // Dictionary needed to grow.
8641 clear_storage();
8642 set_storage(*result);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008643 }
8644}
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008645
8646 void increase_index_offset(uint32_t delta) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008647 if (JSObject::kMaxElementCount - index_offset_ < delta) {
8648 index_offset_ = JSObject::kMaxElementCount;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008649 } else {
8650 index_offset_ += delta;
8651 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008652 }
8653
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008654 Handle<JSArray> ToArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008655 Handle<JSArray> array = isolate_->factory()->NewJSArray(0);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008656 Handle<Object> length =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008657 isolate_->factory()->NewNumber(static_cast<double>(index_offset_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008658 Handle<Map> map;
8659 if (fast_elements_) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008660 map = isolate_->factory()->GetFastElementsMap(Handle<Map>(array->map()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008661 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008662 map = isolate_->factory()->GetSlowElementsMap(Handle<Map>(array->map()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008663 }
8664 array->set_map(*map);
8665 array->set_length(*length);
8666 array->set_elements(*storage_);
8667 return array;
8668 }
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00008669
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008670 private:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008671 // Convert storage to dictionary mode.
8672 void SetDictionaryMode(uint32_t index) {
8673 ASSERT(fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008674 Handle<FixedArray> current_storage(*storage_);
8675 Handle<NumberDictionary> slow_storage(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008676 isolate_->factory()->NewNumberDictionary(current_storage->length()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008677 uint32_t current_length = static_cast<uint32_t>(current_storage->length());
8678 for (uint32_t i = 0; i < current_length; i++) {
8679 HandleScope loop_scope;
8680 Handle<Object> element(current_storage->get(i));
8681 if (!element->IsTheHole()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008682 Handle<NumberDictionary> new_storage =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008683 isolate_->factory()->DictionaryAtNumberPut(slow_storage, i, element);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008684 if (!new_storage.is_identical_to(slow_storage)) {
8685 slow_storage = loop_scope.CloseAndEscape(new_storage);
8686 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008687 }
8688 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008689 clear_storage();
8690 set_storage(*slow_storage);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008691 fast_elements_ = false;
8692 }
8693
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008694 inline void clear_storage() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008695 isolate_->global_handles()->Destroy(
8696 Handle<Object>::cast(storage_).location());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008697 }
8698
8699 inline void set_storage(FixedArray* storage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008700 storage_ = Handle<FixedArray>::cast(
8701 isolate_->global_handles()->Create(storage));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008702 }
8703
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008704 Isolate* isolate_;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008705 Handle<FixedArray> storage_; // Always a global handle.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008706 // Index after last seen index. Always less than or equal to
8707 // JSObject::kMaxElementCount.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008708 uint32_t index_offset_;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008709 bool fast_elements_;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008710};
8711
8712
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008713static uint32_t EstimateElementCount(Handle<JSArray> array) {
8714 uint32_t length = static_cast<uint32_t>(array->length()->Number());
8715 int element_count = 0;
8716 switch (array->GetElementsKind()) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008717 case JSObject::FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008718 // Fast elements can't have lengths that are not representable by
8719 // a 32-bit signed integer.
8720 ASSERT(static_cast<int32_t>(FixedArray::kMaxLength) >= 0);
8721 int fast_length = static_cast<int>(length);
8722 Handle<FixedArray> elements(FixedArray::cast(array->elements()));
8723 for (int i = 0; i < fast_length; i++) {
8724 if (!elements->get(i)->IsTheHole()) element_count++;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008725 }
ager@chromium.org3811b432009-10-28 14:53:37 +00008726 break;
8727 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008728 case JSObject::DICTIONARY_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008729 Handle<NumberDictionary> dictionary(
8730 NumberDictionary::cast(array->elements()));
8731 int capacity = dictionary->Capacity();
8732 for (int i = 0; i < capacity; i++) {
8733 Handle<Object> key(dictionary->KeyAt(i));
8734 if (dictionary->IsKey(*key)) {
8735 element_count++;
8736 }
8737 }
8738 break;
8739 }
8740 default:
8741 // External arrays are always dense.
8742 return length;
8743 }
8744 // As an estimate, we assume that the prototype doesn't contain any
8745 // inherited elements.
8746 return element_count;
8747}
8748
8749
8750
8751template<class ExternalArrayClass, class ElementType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008752static void IterateExternalArrayElements(Isolate* isolate,
8753 Handle<JSObject> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008754 bool elements_are_ints,
8755 bool elements_are_guaranteed_smis,
8756 ArrayConcatVisitor* visitor) {
8757 Handle<ExternalArrayClass> array(
8758 ExternalArrayClass::cast(receiver->elements()));
8759 uint32_t len = static_cast<uint32_t>(array->length());
8760
8761 ASSERT(visitor != NULL);
8762 if (elements_are_ints) {
8763 if (elements_are_guaranteed_smis) {
8764 for (uint32_t j = 0; j < len; j++) {
8765 HandleScope loop_scope;
8766 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get(j))));
8767 visitor->visit(j, e);
8768 }
8769 } else {
8770 for (uint32_t j = 0; j < len; j++) {
8771 HandleScope loop_scope;
8772 int64_t val = static_cast<int64_t>(array->get(j));
8773 if (Smi::IsValid(static_cast<intptr_t>(val))) {
8774 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
8775 visitor->visit(j, e);
8776 } else {
8777 Handle<Object> e =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008778 isolate->factory()->NewNumber(static_cast<ElementType>(val));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008779 visitor->visit(j, e);
8780 }
8781 }
8782 }
8783 } else {
8784 for (uint32_t j = 0; j < len; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008785 HandleScope loop_scope(isolate);
8786 Handle<Object> e = isolate->factory()->NewNumber(array->get(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008787 visitor->visit(j, e);
8788 }
8789 }
8790}
8791
8792
8793// Used for sorting indices in a List<uint32_t>.
8794static int compareUInt32(const uint32_t* ap, const uint32_t* bp) {
8795 uint32_t a = *ap;
8796 uint32_t b = *bp;
8797 return (a == b) ? 0 : (a < b) ? -1 : 1;
8798}
8799
8800
8801static void CollectElementIndices(Handle<JSObject> object,
8802 uint32_t range,
8803 List<uint32_t>* indices) {
8804 JSObject::ElementsKind kind = object->GetElementsKind();
8805 switch (kind) {
8806 case JSObject::FAST_ELEMENTS: {
8807 Handle<FixedArray> elements(FixedArray::cast(object->elements()));
8808 uint32_t length = static_cast<uint32_t>(elements->length());
8809 if (range < length) length = range;
8810 for (uint32_t i = 0; i < length; i++) {
8811 if (!elements->get(i)->IsTheHole()) {
8812 indices->Add(i);
8813 }
8814 }
8815 break;
8816 }
8817 case JSObject::DICTIONARY_ELEMENTS: {
8818 Handle<NumberDictionary> dict(NumberDictionary::cast(object->elements()));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008819 uint32_t capacity = dict->Capacity();
8820 for (uint32_t j = 0; j < capacity; j++) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008821 HandleScope loop_scope;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008822 Handle<Object> k(dict->KeyAt(j));
8823 if (dict->IsKey(*k)) {
8824 ASSERT(k->IsNumber());
8825 uint32_t index = static_cast<uint32_t>(k->Number());
8826 if (index < range) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008827 indices->Add(index);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008828 }
8829 }
8830 }
8831 break;
8832 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008833 default: {
8834 int dense_elements_length;
8835 switch (kind) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00008836 case JSObject::EXTERNAL_PIXEL_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008837 dense_elements_length =
8838 ExternalPixelArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008839 break;
8840 }
8841 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008842 dense_elements_length =
8843 ExternalByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008844 break;
8845 }
8846 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008847 dense_elements_length =
8848 ExternalUnsignedByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008849 break;
8850 }
8851 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008852 dense_elements_length =
8853 ExternalShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008854 break;
8855 }
8856 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008857 dense_elements_length =
8858 ExternalUnsignedShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008859 break;
8860 }
8861 case JSObject::EXTERNAL_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008862 dense_elements_length =
8863 ExternalIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008864 break;
8865 }
8866 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008867 dense_elements_length =
8868 ExternalUnsignedIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008869 break;
8870 }
8871 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008872 dense_elements_length =
8873 ExternalFloatArray::cast(object->elements())->length();
8874 break;
8875 }
8876 case JSObject::EXTERNAL_DOUBLE_ELEMENTS: {
8877 dense_elements_length =
8878 ExternalDoubleArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008879 break;
8880 }
8881 default:
8882 UNREACHABLE();
8883 dense_elements_length = 0;
8884 break;
8885 }
8886 uint32_t length = static_cast<uint32_t>(dense_elements_length);
8887 if (range <= length) {
8888 length = range;
8889 // We will add all indices, so we might as well clear it first
8890 // and avoid duplicates.
8891 indices->Clear();
8892 }
8893 for (uint32_t i = 0; i < length; i++) {
8894 indices->Add(i);
8895 }
8896 if (length == range) return; // All indices accounted for already.
8897 break;
8898 }
8899 }
8900
8901 Handle<Object> prototype(object->GetPrototype());
8902 if (prototype->IsJSObject()) {
8903 // The prototype will usually have no inherited element indices,
8904 // but we have to check.
8905 CollectElementIndices(Handle<JSObject>::cast(prototype), range, indices);
8906 }
8907}
8908
8909
8910/**
8911 * A helper function that visits elements of a JSArray in numerical
8912 * order.
8913 *
8914 * The visitor argument called for each existing element in the array
8915 * with the element index and the element's value.
8916 * Afterwards it increments the base-index of the visitor by the array
8917 * length.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008918 * Returns false if any access threw an exception, otherwise true.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008919 */
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008920static bool IterateElements(Isolate* isolate,
8921 Handle<JSArray> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008922 ArrayConcatVisitor* visitor) {
8923 uint32_t length = static_cast<uint32_t>(receiver->length()->Number());
8924 switch (receiver->GetElementsKind()) {
8925 case JSObject::FAST_ELEMENTS: {
8926 // Run through the elements FixedArray and use HasElement and GetElement
8927 // to check the prototype for missing elements.
8928 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
8929 int fast_length = static_cast<int>(length);
8930 ASSERT(fast_length <= elements->length());
8931 for (int j = 0; j < fast_length; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008932 HandleScope loop_scope(isolate);
8933 Handle<Object> element_value(elements->get(j), isolate);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008934 if (!element_value->IsTheHole()) {
8935 visitor->visit(j, element_value);
8936 } else if (receiver->HasElement(j)) {
8937 // Call GetElement on receiver, not its prototype, or getters won't
8938 // have the correct receiver.
8939 element_value = GetElement(receiver, j);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008940 if (element_value.is_null()) return false;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008941 visitor->visit(j, element_value);
8942 }
8943 }
8944 break;
8945 }
8946 case JSObject::DICTIONARY_ELEMENTS: {
8947 Handle<NumberDictionary> dict(receiver->element_dictionary());
8948 List<uint32_t> indices(dict->Capacity() / 2);
8949 // Collect all indices in the object and the prototypes less
8950 // than length. This might introduce duplicates in the indices list.
8951 CollectElementIndices(receiver, length, &indices);
8952 indices.Sort(&compareUInt32);
8953 int j = 0;
8954 int n = indices.length();
8955 while (j < n) {
8956 HandleScope loop_scope;
8957 uint32_t index = indices[j];
8958 Handle<Object> element = GetElement(receiver, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008959 if (element.is_null()) return false;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008960 visitor->visit(index, element);
8961 // Skip to next different index (i.e., omit duplicates).
8962 do {
8963 j++;
8964 } while (j < n && indices[j] == index);
8965 }
8966 break;
8967 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00008968 case JSObject::EXTERNAL_PIXEL_ELEMENTS: {
8969 Handle<ExternalPixelArray> pixels(ExternalPixelArray::cast(
8970 receiver->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008971 for (uint32_t j = 0; j < length; j++) {
8972 Handle<Smi> e(Smi::FromInt(pixels->get(j)));
8973 visitor->visit(j, e);
8974 }
8975 break;
8976 }
8977 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
8978 IterateExternalArrayElements<ExternalByteArray, int8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008979 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008980 break;
8981 }
8982 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
8983 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008984 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008985 break;
8986 }
8987 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
8988 IterateExternalArrayElements<ExternalShortArray, int16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008989 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008990 break;
8991 }
8992 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
8993 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008994 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008995 break;
8996 }
8997 case JSObject::EXTERNAL_INT_ELEMENTS: {
8998 IterateExternalArrayElements<ExternalIntArray, int32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008999 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009000 break;
9001 }
9002 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
9003 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009004 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009005 break;
9006 }
9007 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
9008 IterateExternalArrayElements<ExternalFloatArray, float>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009009 isolate, receiver, false, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009010 break;
9011 }
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009012 case JSObject::EXTERNAL_DOUBLE_ELEMENTS: {
9013 IterateExternalArrayElements<ExternalDoubleArray, double>(
9014 isolate, receiver, false, false, visitor);
9015 break;
9016 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009017 default:
9018 UNREACHABLE();
9019 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009020 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009021 visitor->increase_index_offset(length);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009022 return true;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009023}
9024
9025
9026/**
9027 * Array::concat implementation.
9028 * See ECMAScript 262, 15.4.4.4.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009029 * TODO(581): Fix non-compliance for very large concatenations and update to
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009030 * following the ECMAScript 5 specification.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009031 */
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009032RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConcat) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009033 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009034 HandleScope handle_scope(isolate);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009035
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009036 CONVERT_ARG_CHECKED(JSArray, arguments, 0);
9037 int argument_count = static_cast<int>(arguments->length()->Number());
9038 RUNTIME_ASSERT(arguments->HasFastElements());
9039 Handle<FixedArray> elements(FixedArray::cast(arguments->elements()));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009040
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009041 // Pass 1: estimate the length and number of elements of the result.
9042 // The actual length can be larger if any of the arguments have getters
9043 // that mutate other arguments (but will otherwise be precise).
9044 // The number of elements is precise if there are no inherited elements.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009045
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009046 uint32_t estimate_result_length = 0;
9047 uint32_t estimate_nof_elements = 0;
9048 {
9049 for (int i = 0; i < argument_count; i++) {
9050 HandleScope loop_scope;
9051 Handle<Object> obj(elements->get(i));
9052 uint32_t length_estimate;
9053 uint32_t element_estimate;
9054 if (obj->IsJSArray()) {
9055 Handle<JSArray> array(Handle<JSArray>::cast(obj));
9056 length_estimate =
9057 static_cast<uint32_t>(array->length()->Number());
9058 element_estimate =
9059 EstimateElementCount(array);
9060 } else {
9061 length_estimate = 1;
9062 element_estimate = 1;
9063 }
9064 // Avoid overflows by capping at kMaxElementCount.
9065 if (JSObject::kMaxElementCount - estimate_result_length <
9066 length_estimate) {
9067 estimate_result_length = JSObject::kMaxElementCount;
9068 } else {
9069 estimate_result_length += length_estimate;
9070 }
9071 if (JSObject::kMaxElementCount - estimate_nof_elements <
9072 element_estimate) {
9073 estimate_nof_elements = JSObject::kMaxElementCount;
9074 } else {
9075 estimate_nof_elements += element_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009076 }
9077 }
9078 }
9079
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009080 // If estimated number of elements is more than half of length, a
9081 // fixed array (fast case) is more time and space-efficient than a
9082 // dictionary.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009083 bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009084
9085 Handle<FixedArray> storage;
9086 if (fast_case) {
9087 // The backing storage array must have non-existing elements to
9088 // preserve holes across concat operations.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009089 storage = isolate->factory()->NewFixedArrayWithHoles(
9090 estimate_result_length);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009091 } else {
9092 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
9093 uint32_t at_least_space_for = estimate_nof_elements +
9094 (estimate_nof_elements >> 2);
9095 storage = Handle<FixedArray>::cast(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009096 isolate->factory()->NewNumberDictionary(at_least_space_for));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009097 }
9098
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009099 ArrayConcatVisitor visitor(isolate, storage, fast_case);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009100
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009101 for (int i = 0; i < argument_count; i++) {
9102 Handle<Object> obj(elements->get(i));
9103 if (obj->IsJSArray()) {
9104 Handle<JSArray> array = Handle<JSArray>::cast(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009105 if (!IterateElements(isolate, array, &visitor)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009106 return Failure::Exception();
9107 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009108 } else {
9109 visitor.visit(0, obj);
9110 visitor.increase_index_offset(1);
9111 }
9112 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009113
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009114 return *visitor.ToArray();
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009115}
9116
9117
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009118// This will not allocate (flatten the string), but it may run
9119// very slowly for very deeply nested ConsStrings. For debugging use only.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009120RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009121 NoHandleAllocation ha;
9122 ASSERT(args.length() == 1);
9123
9124 CONVERT_CHECKED(String, string, args[0]);
9125 StringInputBuffer buffer(string);
9126 while (buffer.has_more()) {
9127 uint16_t character = buffer.GetNext();
9128 PrintF("%c", character);
9129 }
9130 return string;
9131}
9132
ager@chromium.org5ec48922009-05-05 07:25:34 +00009133// Moves all own elements of an object, that are below a limit, to positions
9134// starting at zero. All undefined values are placed after non-undefined values,
9135// and are followed by non-existing element. Does not change the length
9136// property.
9137// Returns the number of non-undefined elements collected.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009138RUNTIME_FUNCTION(MaybeObject*, Runtime_RemoveArrayHoles) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00009139 ASSERT(args.length() == 2);
9140 CONVERT_CHECKED(JSObject, object, args[0]);
9141 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
9142 return object->PrepareElementsForSort(limit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009143}
9144
9145
9146// Move contents of argument 0 (an array) to argument 1 (an array)
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009147RUNTIME_FUNCTION(MaybeObject*, Runtime_MoveArrayContents) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009148 ASSERT(args.length() == 2);
9149 CONVERT_CHECKED(JSArray, from, args[0]);
9150 CONVERT_CHECKED(JSArray, to, args[1]);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009151 HeapObject* new_elements = from->elements();
lrn@chromium.org303ada72010-10-27 09:33:13 +00009152 MaybeObject* maybe_new_map;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009153 if (new_elements->map() == isolate->heap()->fixed_array_map() ||
9154 new_elements->map() == isolate->heap()->fixed_cow_array_map()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009155 maybe_new_map = to->map()->GetFastElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009156 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009157 maybe_new_map = to->map()->GetSlowElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009158 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009159 Object* new_map;
9160 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009161 to->set_map(Map::cast(new_map));
9162 to->set_elements(new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009163 to->set_length(from->length());
lrn@chromium.org303ada72010-10-27 09:33:13 +00009164 Object* obj;
9165 { MaybeObject* maybe_obj = from->ResetElements();
9166 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9167 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009168 from->set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009169 return to;
9170}
9171
9172
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009173// How many elements does this object/array have?
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009174RUNTIME_FUNCTION(MaybeObject*, Runtime_EstimateNumberOfElements) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009175 ASSERT(args.length() == 1);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009176 CONVERT_CHECKED(JSObject, object, args[0]);
9177 HeapObject* elements = object->elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009178 if (elements->IsDictionary()) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009179 return Smi::FromInt(NumberDictionary::cast(elements)->NumberOfElements());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009180 } else if (object->IsJSArray()) {
9181 return JSArray::cast(object)->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009182 } else {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009183 return Smi::FromInt(FixedArray::cast(elements)->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009184 }
9185}
9186
9187
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009188RUNTIME_FUNCTION(MaybeObject*, Runtime_SwapElements) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009189 HandleScope handle_scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009190
9191 ASSERT_EQ(3, args.length());
9192
ager@chromium.orgac091b72010-05-05 07:34:42 +00009193 CONVERT_ARG_CHECKED(JSObject, object, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009194 Handle<Object> key1 = args.at<Object>(1);
9195 Handle<Object> key2 = args.at<Object>(2);
9196
9197 uint32_t index1, index2;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009198 if (!key1->ToArrayIndex(&index1)
9199 || !key2->ToArrayIndex(&index2)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009200 return isolate->ThrowIllegalOperation();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009201 }
9202
ager@chromium.orgac091b72010-05-05 07:34:42 +00009203 Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
9204 Handle<Object> tmp1 = GetElement(jsobject, index1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009205 RETURN_IF_EMPTY_HANDLE(isolate, tmp1);
ager@chromium.orgac091b72010-05-05 07:34:42 +00009206 Handle<Object> tmp2 = GetElement(jsobject, index2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009207 RETURN_IF_EMPTY_HANDLE(isolate, tmp2);
ager@chromium.orgac091b72010-05-05 07:34:42 +00009208
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009209 RETURN_IF_EMPTY_HANDLE(isolate,
9210 SetElement(jsobject, index1, tmp2, kStrictMode));
9211 RETURN_IF_EMPTY_HANDLE(isolate,
9212 SetElement(jsobject, index2, tmp1, kStrictMode));
ager@chromium.orgac091b72010-05-05 07:34:42 +00009213
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009214 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009215}
9216
9217
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009218// Returns an array that tells you where in the [0, length) interval an array
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009219// might have elements. Can either return keys (positive integers) or
9220// intervals (pair of a negative integer (-start-1) followed by a
9221// positive (length)) or undefined values.
9222// Intervals can span over some keys that are not in the object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009223RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArrayKeys) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009224 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009225 HandleScope scope(isolate);
ager@chromium.org5ec48922009-05-05 07:25:34 +00009226 CONVERT_ARG_CHECKED(JSObject, array, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009227 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009228 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009229 // Create an array and get all the keys into it, then remove all the
9230 // keys that are not integers in the range 0 to length-1.
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009231 Handle<FixedArray> keys = GetKeysInFixedArrayFor(array, INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009232 int keys_length = keys->length();
9233 for (int i = 0; i < keys_length; i++) {
9234 Object* key = keys->get(i);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009235 uint32_t index = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009236 if (!key->ToArrayIndex(&index) || index >= length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009237 // Zap invalid keys.
9238 keys->set_undefined(i);
9239 }
9240 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009241 return *isolate->factory()->NewJSArrayWithElements(keys);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009242 } else {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009243 ASSERT(array->HasFastElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009244 Handle<FixedArray> single_interval = isolate->factory()->NewFixedArray(2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009245 // -1 means start of array.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009246 single_interval->set(0, Smi::FromInt(-1));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009247 uint32_t actual_length =
9248 static_cast<uint32_t>(FixedArray::cast(array->elements())->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +00009249 uint32_t min_length = actual_length < length ? actual_length : length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009250 Handle<Object> length_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009251 isolate->factory()->NewNumber(static_cast<double>(min_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009252 single_interval->set(1, *length_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009253 return *isolate->factory()->NewJSArrayWithElements(single_interval);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009254 }
9255}
9256
9257
9258// DefineAccessor takes an optional final argument which is the
9259// property attributes (eg, DONT_ENUM, DONT_DELETE). IMPORTANT: due
9260// to the way accessors are implemented, it is set for both the getter
9261// and setter on the first call to DefineAccessor and ignored on
9262// subsequent calls.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009263RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009264 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
9265 // Compute attributes.
9266 PropertyAttributes attributes = NONE;
9267 if (args.length() == 5) {
9268 CONVERT_CHECKED(Smi, attrs, args[4]);
9269 int value = attrs->value();
9270 // Only attribute bits should be set.
9271 ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
9272 attributes = static_cast<PropertyAttributes>(value);
9273 }
9274
9275 CONVERT_CHECKED(JSObject, obj, args[0]);
9276 CONVERT_CHECKED(String, name, args[1]);
9277 CONVERT_CHECKED(Smi, flag, args[2]);
9278 CONVERT_CHECKED(JSFunction, fun, args[3]);
9279 return obj->DefineAccessor(name, flag->value() == 0, fun, attributes);
9280}
9281
9282
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009283RUNTIME_FUNCTION(MaybeObject*, Runtime_LookupAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009284 ASSERT(args.length() == 3);
9285 CONVERT_CHECKED(JSObject, obj, args[0]);
9286 CONVERT_CHECKED(String, name, args[1]);
9287 CONVERT_CHECKED(Smi, flag, args[2]);
9288 return obj->LookupAccessor(name, flag->value() == 0);
9289}
9290
9291
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009292#ifdef ENABLE_DEBUGGER_SUPPORT
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009293RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugBreak) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009294 ASSERT(args.length() == 0);
9295 return Execution::DebugBreakHelper();
9296}
9297
9298
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009299// Helper functions for wrapping and unwrapping stack frame ids.
9300static Smi* WrapFrameId(StackFrame::Id id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +00009301 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009302 return Smi::FromInt(id >> 2);
9303}
9304
9305
9306static StackFrame::Id UnwrapFrameId(Smi* wrapped) {
9307 return static_cast<StackFrame::Id>(wrapped->value() << 2);
9308}
9309
9310
9311// Adds a JavaScript function as a debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +00009312// args[0]: debug event listener function to set or null or undefined for
9313// clearing the event listener function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009314// args[1]: object supplied during callback
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009315RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDebugEventListener) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009316 ASSERT(args.length() == 2);
iposva@chromium.org245aa852009-02-10 00:49:54 +00009317 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
9318 args[0]->IsUndefined() ||
9319 args[0]->IsNull());
9320 Handle<Object> callback = args.at<Object>(0);
9321 Handle<Object> data = args.at<Object>(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009322 isolate->debugger()->SetEventListener(callback, data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009323
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009324 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009325}
9326
9327
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009328RUNTIME_FUNCTION(MaybeObject*, Runtime_Break) {
mads.s.ager31e71382008-08-13 09:32:07 +00009329 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009330 isolate->stack_guard()->DebugBreak();
9331 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009332}
9333
9334
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009335static MaybeObject* DebugLookupResultValue(Heap* heap,
9336 Object* receiver,
9337 String* name,
lrn@chromium.org303ada72010-10-27 09:33:13 +00009338 LookupResult* result,
9339 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009340 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009341 switch (result->type()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009342 case NORMAL:
9343 value = result->holder()->GetNormalizedProperty(result);
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009344 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009345 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009346 }
9347 return value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009348 case FIELD:
9349 value =
9350 JSObject::cast(
9351 result->holder())->FastPropertyAt(result->GetFieldIndex());
9352 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009353 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009354 }
9355 return value;
9356 case CONSTANT_FUNCTION:
9357 return result->GetConstantFunction();
9358 case CALLBACKS: {
9359 Object* structure = result->GetCallbackObject();
ager@chromium.orgea91cc52011-05-23 06:06:11 +00009360 if (structure->IsForeign() || structure->IsAccessorInfo()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009361 MaybeObject* maybe_value = receiver->GetPropertyWithCallback(
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00009362 receiver, structure, name, result->holder());
lrn@chromium.org303ada72010-10-27 09:33:13 +00009363 if (!maybe_value->ToObject(&value)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009364 if (maybe_value->IsRetryAfterGC()) return maybe_value;
lrn@chromium.org303ada72010-10-27 09:33:13 +00009365 ASSERT(maybe_value->IsException());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009366 maybe_value = heap->isolate()->pending_exception();
9367 heap->isolate()->clear_pending_exception();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009368 if (caught_exception != NULL) {
9369 *caught_exception = true;
9370 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009371 return maybe_value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009372 }
9373 return value;
9374 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009375 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009376 }
9377 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009378 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009379 case MAP_TRANSITION:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00009380 case EXTERNAL_ARRAY_TRANSITION:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009381 case CONSTANT_TRANSITION:
9382 case NULL_DESCRIPTOR:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009383 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009384 default:
9385 UNREACHABLE();
9386 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009387 UNREACHABLE();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009388 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009389}
9390
9391
ager@chromium.org32912102009-01-16 10:38:43 +00009392// Get debugger related details for an object property.
9393// args[0]: object holding property
9394// args[1]: name of the property
9395//
9396// The array returned contains the following information:
9397// 0: Property value
9398// 1: Property details
9399// 2: Property value is exception
9400// 3: Getter function if defined
9401// 4: Setter function if defined
9402// Items 2-4 are only filled if the property has either a getter or a setter
9403// defined through __defineGetter__ and/or __defineSetter__.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009404RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPropertyDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009405 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009406
9407 ASSERT(args.length() == 2);
9408
9409 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9410 CONVERT_ARG_CHECKED(String, name, 1);
9411
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00009412 // Make sure to set the current context to the context before the debugger was
9413 // entered (if the debugger is entered). The reason for switching context here
9414 // is that for some property lookups (accessors and interceptors) callbacks
9415 // into the embedding application can occour, and the embedding application
9416 // could have the assumption that its own global context is the current
9417 // context and not some internal debugger context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009418 SaveContext save(isolate);
9419 if (isolate->debug()->InDebugger()) {
9420 isolate->set_context(*isolate->debug()->debugger_entry()->GetContext());
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00009421 }
9422
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009423 // Skip the global proxy as it has no properties and always delegates to the
9424 // real global object.
9425 if (obj->IsJSGlobalProxy()) {
9426 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
9427 }
9428
9429
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009430 // Check if the name is trivially convertible to an index and get the element
9431 // if so.
9432 uint32_t index;
9433 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009434 Handle<FixedArray> details = isolate->factory()->NewFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009435 Object* element_or_char;
9436 { MaybeObject* maybe_element_or_char =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009437 Runtime::GetElementOrCharAt(isolate, obj, index);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009438 if (!maybe_element_or_char->ToObject(&element_or_char)) {
9439 return maybe_element_or_char;
9440 }
9441 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00009442 details->set(0, element_or_char);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009443 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009444 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009445 }
9446
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009447 // Find the number of objects making up this.
9448 int length = LocalPrototypeChainLength(*obj);
9449
9450 // Try local lookup on each of the objects.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009451 Handle<JSObject> jsproto = obj;
9452 for (int i = 0; i < length; i++) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009453 LookupResult result;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009454 jsproto->LocalLookup(*name, &result);
9455 if (result.IsProperty()) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009456 // LookupResult is not GC safe as it holds raw object pointers.
9457 // GC can happen later in this code so put the required fields into
9458 // local variables using handles when required for later use.
9459 PropertyType result_type = result.type();
9460 Handle<Object> result_callback_obj;
9461 if (result_type == CALLBACKS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009462 result_callback_obj = Handle<Object>(result.GetCallbackObject(),
9463 isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009464 }
9465 Smi* property_details = result.GetPropertyDetails().AsSmi();
9466 // DebugLookupResultValue can cause GC so details from LookupResult needs
9467 // to be copied to handles before this.
9468 bool caught_exception = false;
lrn@chromium.org303ada72010-10-27 09:33:13 +00009469 Object* raw_value;
9470 { MaybeObject* maybe_raw_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009471 DebugLookupResultValue(isolate->heap(), *obj, *name,
9472 &result, &caught_exception);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009473 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
9474 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009475 Handle<Object> value(raw_value, isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009476
9477 // If the callback object is a fixed array then it contains JavaScript
9478 // getter and/or setter.
9479 bool hasJavaScriptAccessors = result_type == CALLBACKS &&
9480 result_callback_obj->IsFixedArray();
9481 Handle<FixedArray> details =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009482 isolate->factory()->NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009483 details->set(0, *value);
9484 details->set(1, property_details);
9485 if (hasJavaScriptAccessors) {
9486 details->set(2,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009487 caught_exception ? isolate->heap()->true_value()
9488 : isolate->heap()->false_value());
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009489 details->set(3, FixedArray::cast(*result_callback_obj)->get(0));
9490 details->set(4, FixedArray::cast(*result_callback_obj)->get(1));
9491 }
9492
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009493 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009494 }
9495 if (i < length - 1) {
9496 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
9497 }
9498 }
9499
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009500 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009501}
9502
9503
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009504RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetProperty) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009505 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009506
9507 ASSERT(args.length() == 2);
9508
9509 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9510 CONVERT_ARG_CHECKED(String, name, 1);
9511
9512 LookupResult result;
9513 obj->Lookup(*name, &result);
9514 if (result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009515 return DebugLookupResultValue(isolate->heap(), *obj, *name, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009516 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009517 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009518}
9519
9520
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009521// Return the property type calculated from the property details.
9522// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009523RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyTypeFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009524 ASSERT(args.length() == 1);
9525 CONVERT_CHECKED(Smi, details, args[0]);
9526 PropertyType type = PropertyDetails(details).type();
9527 return Smi::FromInt(static_cast<int>(type));
9528}
9529
9530
9531// Return the property attribute calculated from the property details.
9532// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009533RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyAttributesFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009534 ASSERT(args.length() == 1);
9535 CONVERT_CHECKED(Smi, details, args[0]);
9536 PropertyAttributes attributes = PropertyDetails(details).attributes();
9537 return Smi::FromInt(static_cast<int>(attributes));
9538}
9539
9540
9541// Return the property insertion index calculated from the property details.
9542// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009543RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyIndexFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009544 ASSERT(args.length() == 1);
9545 CONVERT_CHECKED(Smi, details, args[0]);
9546 int index = PropertyDetails(details).index();
9547 return Smi::FromInt(index);
9548}
9549
9550
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009551// Return property value from named interceptor.
9552// args[0]: object
9553// args[1]: property name
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009554RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugNamedInterceptorPropertyValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009555 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009556 ASSERT(args.length() == 2);
9557 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9558 RUNTIME_ASSERT(obj->HasNamedInterceptor());
9559 CONVERT_ARG_CHECKED(String, name, 1);
9560
9561 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009562 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009563}
9564
9565
9566// Return element value from indexed interceptor.
9567// args[0]: object
9568// args[1]: index
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009569RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugIndexedInterceptorElementValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009570 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009571 ASSERT(args.length() == 2);
9572 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9573 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
9574 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
9575
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009576 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009577}
9578
9579
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009580RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckExecutionState) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009581 ASSERT(args.length() >= 1);
9582 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +00009583 // Check that the break id is valid.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009584 if (isolate->debug()->break_id() == 0 ||
9585 break_id != isolate->debug()->break_id()) {
9586 return isolate->Throw(
9587 isolate->heap()->illegal_execution_state_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009588 }
9589
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009590 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009591}
9592
9593
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009594RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009595 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009596 ASSERT(args.length() == 1);
9597
9598 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009599 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009600 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
9601 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +00009602 if (!maybe_result->ToObject(&result)) return maybe_result;
9603 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009604
9605 // Count all frames which are relevant to debugging stack trace.
9606 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009607 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00009608 if (id == StackFrame::NO_ID) {
9609 // If there is no JavaScript stack frame count is 0.
9610 return Smi::FromInt(0);
9611 }
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009612 for (JavaScriptFrameIterator it(isolate, id); !it.done(); it.Advance()) n++;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009613 return Smi::FromInt(n);
9614}
9615
9616
9617static const int kFrameDetailsFrameIdIndex = 0;
9618static const int kFrameDetailsReceiverIndex = 1;
9619static const int kFrameDetailsFunctionIndex = 2;
9620static const int kFrameDetailsArgumentCountIndex = 3;
9621static const int kFrameDetailsLocalCountIndex = 4;
9622static const int kFrameDetailsSourcePositionIndex = 5;
9623static const int kFrameDetailsConstructCallIndex = 6;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009624static const int kFrameDetailsAtReturnIndex = 7;
9625static const int kFrameDetailsDebuggerFrameIndex = 8;
9626static const int kFrameDetailsFirstDynamicIndex = 9;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009627
9628// Return an array with frame details
9629// args[0]: number: break id
9630// args[1]: number: frame index
9631//
9632// The array returned contains the following information:
9633// 0: Frame id
9634// 1: Receiver
9635// 2: Function
9636// 3: Argument count
9637// 4: Local count
9638// 5: Source position
9639// 6: Constructor call
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009640// 7: Is at return
9641// 8: Debugger frame
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009642// Arguments name, value
9643// Locals name, value
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009644// Return value if any
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009645RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009646 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009647 ASSERT(args.length() == 2);
9648
9649 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009650 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009651 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
9652 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +00009653 if (!maybe_check->ToObject(&check)) return maybe_check;
9654 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009655 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009656 Heap* heap = isolate->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009657
9658 // Find the relevant frame with the requested index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009659 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00009660 if (id == StackFrame::NO_ID) {
9661 // If there are no JavaScript stack frames return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009662 return heap->undefined_value();
ager@chromium.org8bb60582008-12-11 12:02:20 +00009663 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009664 int count = 0;
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009665 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009666 for (; !it.done(); it.Advance()) {
9667 if (count == index) break;
9668 count++;
9669 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009670 if (it.done()) return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009671
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009672 bool is_optimized_frame =
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009673 it.frame()->LookupCode()->kind() == Code::OPTIMIZED_FUNCTION;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009674
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009675 // Traverse the saved contexts chain to find the active context for the
9676 // selected frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009677 SaveContext* save = isolate->save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009678 while (save != NULL && !save->below(it.frame())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009679 save = save->prev();
9680 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009681 ASSERT(save != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009682
9683 // Get the frame id.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009684 Handle<Object> frame_id(WrapFrameId(it.frame()->id()), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009685
9686 // Find source position.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009687 int position =
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009688 it.frame()->LookupCode()->SourcePosition(it.frame()->pc());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009689
9690 // Check for constructor frame.
9691 bool constructor = it.frame()->IsConstructor();
9692
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009693 // Get scope info and read from it for local variable information.
9694 Handle<JSFunction> function(JSFunction::cast(it.frame()->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +00009695 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009696 ScopeInfo<> info(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009697
9698 // Get the context.
9699 Handle<Context> context(Context::cast(it.frame()->context()));
9700
9701 // Get the locals names and values into a temporary array.
9702 //
9703 // TODO(1240907): Hide compiler-introduced stack variables
9704 // (e.g. .result)? For users of the debugger, they will probably be
9705 // confusing.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009706 Handle<FixedArray> locals =
9707 isolate->factory()->NewFixedArray(info.NumberOfLocals() * 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009708
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009709 // Fill in the names of the locals.
9710 for (int i = 0; i < info.NumberOfLocals(); i++) {
9711 locals->set(i * 2, *info.LocalName(i));
9712 }
9713
9714 // Fill in the values of the locals.
9715 for (int i = 0; i < info.NumberOfLocals(); i++) {
9716 if (is_optimized_frame) {
9717 // If we are inspecting an optimized frame use undefined as the
9718 // value for all locals.
9719 //
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009720 // TODO(1140): We should be able to get the correct values
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009721 // for locals in optimized frames.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009722 locals->set(i * 2 + 1, isolate->heap()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009723 } else if (i < info.number_of_stack_slots()) {
9724 // Get the value from the stack.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009725 locals->set(i * 2 + 1, it.frame()->GetExpression(i));
9726 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009727 // Traverse the context chain to the function context as all local
9728 // variables stored in the context will be on the function context.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009729 Handle<String> name = info.LocalName(i);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009730 while (!context->is_function_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009731 context = Handle<Context>(context->previous());
9732 }
9733 ASSERT(context->is_function_context());
9734 locals->set(i * 2 + 1,
ager@chromium.orgb5737492010-07-15 09:29:43 +00009735 context->get(scope_info->ContextSlotIndex(*name, NULL)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009736 }
9737 }
9738
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009739 // Check whether this frame is positioned at return. If not top
9740 // frame or if the frame is optimized it cannot be at a return.
9741 bool at_return = false;
9742 if (!is_optimized_frame && index == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009743 at_return = isolate->debug()->IsBreakAtReturn(it.frame());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009744 }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009745
9746 // If positioned just before return find the value to be returned and add it
9747 // to the frame information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009748 Handle<Object> return_value = isolate->factory()->undefined_value();
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009749 if (at_return) {
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009750 StackFrameIterator it2(isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009751 Address internal_frame_sp = NULL;
9752 while (!it2.done()) {
9753 if (it2.frame()->is_internal()) {
9754 internal_frame_sp = it2.frame()->sp();
9755 } else {
9756 if (it2.frame()->is_java_script()) {
9757 if (it2.frame()->id() == it.frame()->id()) {
9758 // The internal frame just before the JavaScript frame contains the
9759 // value to return on top. A debug break at return will create an
9760 // internal frame to store the return value (eax/rax/r0) before
9761 // entering the debug break exit frame.
9762 if (internal_frame_sp != NULL) {
9763 return_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009764 Handle<Object>(Memory::Object_at(internal_frame_sp),
9765 isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009766 break;
9767 }
9768 }
9769 }
9770
9771 // Indicate that the previous frame was not an internal frame.
9772 internal_frame_sp = NULL;
9773 }
9774 it2.Advance();
9775 }
9776 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009777
9778 // Now advance to the arguments adapter frame (if any). It contains all
9779 // the provided parameters whereas the function frame always have the number
9780 // of arguments matching the functions parameters. The rest of the
9781 // information (except for what is collected above) is the same.
9782 it.AdvanceToArgumentsFrame();
9783
9784 // Find the number of arguments to fill. At least fill the number of
9785 // parameters for the function and fill more if more parameters are provided.
9786 int argument_count = info.number_of_parameters();
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009787 if (argument_count < it.frame()->ComputeParametersCount()) {
9788 argument_count = it.frame()->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009789 }
9790
9791 // Calculate the size of the result.
9792 int details_size = kFrameDetailsFirstDynamicIndex +
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009793 2 * (argument_count + info.NumberOfLocals()) +
9794 (at_return ? 1 : 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009795 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009796
9797 // Add the frame id.
9798 details->set(kFrameDetailsFrameIdIndex, *frame_id);
9799
9800 // Add the function (same as in function frame).
9801 details->set(kFrameDetailsFunctionIndex, it.frame()->function());
9802
9803 // Add the arguments count.
9804 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
9805
9806 // Add the locals count
9807 details->set(kFrameDetailsLocalCountIndex,
9808 Smi::FromInt(info.NumberOfLocals()));
9809
9810 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +00009811 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009812 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
9813 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009814 details->set(kFrameDetailsSourcePositionIndex, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009815 }
9816
9817 // Add the constructor information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009818 details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(constructor));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009819
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009820 // Add the at return information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009821 details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(at_return));
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009822
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009823 // Add information on whether this frame is invoked in the debugger context.
9824 details->set(kFrameDetailsDebuggerFrameIndex,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009825 heap->ToBoolean(*save->context() ==
9826 *isolate->debug()->debug_context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009827
9828 // Fill the dynamic part.
9829 int details_index = kFrameDetailsFirstDynamicIndex;
9830
9831 // Add arguments name and value.
9832 for (int i = 0; i < argument_count; i++) {
9833 // Name of the argument.
9834 if (i < info.number_of_parameters()) {
9835 details->set(details_index++, *info.parameter_name(i));
9836 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009837 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009838 }
9839
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009840 // Parameter value. If we are inspecting an optimized frame, use
9841 // undefined as the value.
9842 //
9843 // TODO(3141533): We should be able to get the actual parameter
9844 // value for optimized frames.
9845 if (!is_optimized_frame &&
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009846 (i < it.frame()->ComputeParametersCount())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009847 details->set(details_index++, it.frame()->GetParameter(i));
9848 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009849 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009850 }
9851 }
9852
9853 // Add locals name and value from the temporary copy from the function frame.
9854 for (int i = 0; i < info.NumberOfLocals() * 2; i++) {
9855 details->set(details_index++, locals->get(i));
9856 }
9857
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009858 // Add the value being returned.
9859 if (at_return) {
9860 details->set(details_index++, *return_value);
9861 }
9862
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009863 // Add the receiver (same as in function frame).
9864 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
9865 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009866 Handle<Object> receiver(it.frame()->receiver(), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009867 if (!receiver->IsJSObject()) {
9868 // If the receiver is NOT a JSObject we have hit an optimization
9869 // where a value object is not converted into a wrapped JS objects.
9870 // To hide this optimization from the debugger, we wrap the receiver
9871 // by creating correct wrapper object based on the calling frame's
9872 // global context.
9873 it.Advance();
9874 Handle<Context> calling_frames_global_context(
9875 Context::cast(Context::cast(it.frame()->context())->global_context()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009876 receiver =
9877 isolate->factory()->ToObject(receiver, calling_frames_global_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009878 }
9879 details->set(kFrameDetailsReceiverIndex, *receiver);
9880
9881 ASSERT_EQ(details_size, details_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009882 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009883}
9884
9885
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009886// Copy all the context locals into an object used to materialize a scope.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009887static bool CopyContextLocalsToScopeObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009888 Isolate* isolate,
ager@chromium.orgb5737492010-07-15 09:29:43 +00009889 Handle<SerializedScopeInfo> serialized_scope_info,
9890 ScopeInfo<>& scope_info,
9891 Handle<Context> context,
9892 Handle<JSObject> scope_object) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009893 // Fill all context locals to the context extension.
9894 for (int i = Context::MIN_CONTEXT_SLOTS;
9895 i < scope_info.number_of_context_slots();
9896 i++) {
ager@chromium.orgb5737492010-07-15 09:29:43 +00009897 int context_index = serialized_scope_info->ContextSlotIndex(
9898 *scope_info.context_slot_name(i), NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009899
9900 // Don't include the arguments shadow (.arguments) context variable.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009901 if (*scope_info.context_slot_name(i) !=
9902 isolate->heap()->arguments_shadow_symbol()) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009903 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009904 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009905 SetProperty(scope_object,
9906 scope_info.context_slot_name(i),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009907 Handle<Object>(context->get(context_index), isolate),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009908 NONE,
9909 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009910 false);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009911 }
9912 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009913
9914 return true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009915}
9916
9917
9918// Create a plain JSObject which materializes the local scope for the specified
9919// frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009920static Handle<JSObject> MaterializeLocalScope(Isolate* isolate,
9921 JavaScriptFrame* frame) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009922 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009923 Handle<SharedFunctionInfo> shared(function->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +00009924 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
9925 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009926
9927 // Allocate and initialize a JSObject with all the arguments, stack locals
9928 // heap locals and extension properties of the debugged function.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009929 Handle<JSObject> local_scope =
9930 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009931
9932 // First fill all parameters.
9933 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009934 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009935 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009936 SetProperty(local_scope,
9937 scope_info.parameter_name(i),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009938 Handle<Object>(frame->GetParameter(i), isolate),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009939 NONE,
9940 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009941 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009942 }
9943
9944 // Second fill all stack locals.
9945 for (int i = 0; i < scope_info.number_of_stack_slots(); i++) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009946 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009947 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009948 SetProperty(local_scope,
9949 scope_info.stack_slot_name(i),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009950 Handle<Object>(frame->GetExpression(i), isolate),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009951 NONE,
9952 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009953 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009954 }
9955
9956 // Third fill all context locals.
9957 Handle<Context> frame_context(Context::cast(frame->context()));
9958 Handle<Context> function_context(frame_context->fcontext());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009959 if (!CopyContextLocalsToScopeObject(isolate,
9960 serialized_scope_info, scope_info,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009961 function_context, local_scope)) {
9962 return Handle<JSObject>();
9963 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009964
9965 // Finally copy any properties from the function context extension. This will
9966 // be variables introduced by eval.
9967 if (function_context->closure() == *function) {
9968 if (function_context->has_extension() &&
9969 !function_context->IsGlobalContext()) {
9970 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009971 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009972 for (int i = 0; i < keys->length(); i++) {
9973 // Names of variables introduced by eval are strings.
9974 ASSERT(keys->get(i)->IsString());
9975 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009976 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009977 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009978 SetProperty(local_scope,
9979 key,
9980 GetProperty(ext, key),
9981 NONE,
9982 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009983 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009984 }
9985 }
9986 }
9987 return local_scope;
9988}
9989
9990
9991// Create a plain JSObject which materializes the closure content for the
9992// context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009993static Handle<JSObject> MaterializeClosure(Isolate* isolate,
9994 Handle<Context> context) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009995 ASSERT(context->is_function_context());
9996
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009997 Handle<SharedFunctionInfo> shared(context->closure()->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +00009998 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
9999 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010000
10001 // Allocate and initialize a JSObject with all the content of theis function
10002 // closure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010003 Handle<JSObject> closure_scope =
10004 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010005
10006 // Check whether the arguments shadow object exists.
10007 int arguments_shadow_index =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010008 shared->scope_info()->ContextSlotIndex(
10009 isolate->heap()->arguments_shadow_symbol(), NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010010 if (arguments_shadow_index >= 0) {
10011 // In this case all the arguments are available in the arguments shadow
10012 // object.
10013 Handle<JSObject> arguments_shadow(
10014 JSObject::cast(context->get(arguments_shadow_index)));
10015 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000010016 // We don't expect exception-throwing getters on the arguments shadow.
10017 Object* element = arguments_shadow->GetElement(i)->ToObjectUnchecked();
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010018 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010019 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010020 SetProperty(closure_scope,
10021 scope_info.parameter_name(i),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010022 Handle<Object>(element, isolate),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010023 NONE,
10024 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010025 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010026 }
10027 }
10028
10029 // Fill all context locals to the context extension.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010030 if (!CopyContextLocalsToScopeObject(isolate,
10031 serialized_scope_info, scope_info,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010032 context, closure_scope)) {
10033 return Handle<JSObject>();
10034 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010035
10036 // Finally copy any properties from the function context extension. This will
10037 // be variables introduced by eval.
10038 if (context->has_extension()) {
10039 Handle<JSObject> ext(JSObject::cast(context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010040 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010041 for (int i = 0; i < keys->length(); i++) {
10042 // Names of variables introduced by eval are strings.
10043 ASSERT(keys->get(i)->IsString());
10044 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010045 RETURN_IF_EMPTY_HANDLE_VALUE(
10046 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010047 SetProperty(closure_scope,
10048 key,
10049 GetProperty(ext, key),
10050 NONE,
10051 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010052 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010053 }
10054 }
10055
10056 return closure_scope;
10057}
10058
10059
10060// Iterate over the actual scopes visible from a stack frame. All scopes are
10061// backed by an actual context except the local scope, which is inserted
10062// "artifically" in the context chain.
10063class ScopeIterator {
10064 public:
10065 enum ScopeType {
10066 ScopeTypeGlobal = 0,
10067 ScopeTypeLocal,
10068 ScopeTypeWith,
ager@chromium.orga1645e22009-09-09 19:27:10 +000010069 ScopeTypeClosure,
10070 // Every catch block contains an implicit with block (its parameter is
10071 // a JSContextExtensionObject) that extends current scope with a variable
10072 // holding exception object. Such with blocks are treated as scopes of their
10073 // own type.
10074 ScopeTypeCatch
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010075 };
10076
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010077 ScopeIterator(Isolate* isolate, JavaScriptFrame* frame)
10078 : isolate_(isolate),
10079 frame_(frame),
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010080 function_(JSFunction::cast(frame->function())),
10081 context_(Context::cast(frame->context())),
10082 local_done_(false),
10083 at_local_(false) {
10084
10085 // Check whether the first scope is actually a local scope.
10086 if (context_->IsGlobalContext()) {
10087 // If there is a stack slot for .result then this local scope has been
10088 // created for evaluating top level code and it is not a real local scope.
10089 // Checking for the existence of .result seems fragile, but the scope info
10090 // saved with the code object does not otherwise have that information.
ager@chromium.orgb5737492010-07-15 09:29:43 +000010091 int index = function_->shared()->scope_info()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010092 StackSlotIndex(isolate_->heap()->result_symbol());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010093 at_local_ = index < 0;
10094 } else if (context_->is_function_context()) {
10095 at_local_ = true;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000010096 } else if (context_->closure() != *function_) {
10097 // The context_ is a with block from the outer function.
10098 ASSERT(context_->has_extension());
10099 at_local_ = true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010100 }
10101 }
10102
10103 // More scopes?
10104 bool Done() { return context_.is_null(); }
10105
10106 // Move to the next scope.
10107 void Next() {
10108 // If at a local scope mark the local scope as passed.
10109 if (at_local_) {
10110 at_local_ = false;
10111 local_done_ = true;
10112
10113 // If the current context is not associated with the local scope the
10114 // current context is the next real scope, so don't move to the next
10115 // context in this case.
10116 if (context_->closure() != *function_) {
10117 return;
10118 }
10119 }
10120
10121 // The global scope is always the last in the chain.
10122 if (context_->IsGlobalContext()) {
10123 context_ = Handle<Context>();
10124 return;
10125 }
10126
10127 // Move to the next context.
10128 if (context_->is_function_context()) {
10129 context_ = Handle<Context>(Context::cast(context_->closure()->context()));
10130 } else {
10131 context_ = Handle<Context>(context_->previous());
10132 }
10133
10134 // If passing the local scope indicate that the current scope is now the
10135 // local scope.
10136 if (!local_done_ &&
10137 (context_->IsGlobalContext() || (context_->is_function_context()))) {
10138 at_local_ = true;
10139 }
10140 }
10141
10142 // Return the type of the current scope.
10143 int Type() {
10144 if (at_local_) {
10145 return ScopeTypeLocal;
10146 }
10147 if (context_->IsGlobalContext()) {
10148 ASSERT(context_->global()->IsGlobalObject());
10149 return ScopeTypeGlobal;
10150 }
10151 if (context_->is_function_context()) {
10152 return ScopeTypeClosure;
10153 }
10154 ASSERT(context_->has_extension());
ager@chromium.orga1645e22009-09-09 19:27:10 +000010155 // Current scope is either an explicit with statement or a with statement
10156 // implicitely generated for a catch block.
10157 // If the extension object here is a JSContextExtensionObject then
10158 // current with statement is one frome a catch block otherwise it's a
10159 // regular with statement.
10160 if (context_->extension()->IsJSContextExtensionObject()) {
10161 return ScopeTypeCatch;
10162 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010163 return ScopeTypeWith;
10164 }
10165
10166 // Return the JavaScript object with the content of the current scope.
10167 Handle<JSObject> ScopeObject() {
10168 switch (Type()) {
10169 case ScopeIterator::ScopeTypeGlobal:
10170 return Handle<JSObject>(CurrentContext()->global());
10171 break;
10172 case ScopeIterator::ScopeTypeLocal:
10173 // Materialize the content of the local scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010174 return MaterializeLocalScope(isolate_, frame_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010175 break;
10176 case ScopeIterator::ScopeTypeWith:
ager@chromium.orga1645e22009-09-09 19:27:10 +000010177 case ScopeIterator::ScopeTypeCatch:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010178 // Return the with object.
10179 return Handle<JSObject>(CurrentContext()->extension());
10180 break;
10181 case ScopeIterator::ScopeTypeClosure:
10182 // Materialize the content of the closure scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010183 return MaterializeClosure(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010184 break;
10185 }
10186 UNREACHABLE();
10187 return Handle<JSObject>();
10188 }
10189
10190 // Return the context for this scope. For the local context there might not
10191 // be an actual context.
10192 Handle<Context> CurrentContext() {
10193 if (at_local_ && context_->closure() != *function_) {
10194 return Handle<Context>();
10195 }
10196 return context_;
10197 }
10198
10199#ifdef DEBUG
10200 // Debug print of the content of the current scope.
10201 void DebugPrint() {
10202 switch (Type()) {
10203 case ScopeIterator::ScopeTypeGlobal:
10204 PrintF("Global:\n");
10205 CurrentContext()->Print();
10206 break;
10207
10208 case ScopeIterator::ScopeTypeLocal: {
10209 PrintF("Local:\n");
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010210 ScopeInfo<> scope_info(function_->shared()->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010211 scope_info.Print();
10212 if (!CurrentContext().is_null()) {
10213 CurrentContext()->Print();
10214 if (CurrentContext()->has_extension()) {
10215 Handle<JSObject> extension =
10216 Handle<JSObject>(CurrentContext()->extension());
10217 if (extension->IsJSContextExtensionObject()) {
10218 extension->Print();
10219 }
10220 }
10221 }
10222 break;
10223 }
10224
10225 case ScopeIterator::ScopeTypeWith: {
10226 PrintF("With:\n");
10227 Handle<JSObject> extension =
10228 Handle<JSObject>(CurrentContext()->extension());
10229 extension->Print();
10230 break;
10231 }
10232
ager@chromium.orga1645e22009-09-09 19:27:10 +000010233 case ScopeIterator::ScopeTypeCatch: {
10234 PrintF("Catch:\n");
10235 Handle<JSObject> extension =
10236 Handle<JSObject>(CurrentContext()->extension());
10237 extension->Print();
10238 break;
10239 }
10240
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010241 case ScopeIterator::ScopeTypeClosure: {
10242 PrintF("Closure:\n");
10243 CurrentContext()->Print();
10244 if (CurrentContext()->has_extension()) {
10245 Handle<JSObject> extension =
10246 Handle<JSObject>(CurrentContext()->extension());
10247 if (extension->IsJSContextExtensionObject()) {
10248 extension->Print();
10249 }
10250 }
10251 break;
10252 }
10253
10254 default:
10255 UNREACHABLE();
10256 }
10257 PrintF("\n");
10258 }
10259#endif
10260
10261 private:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010262 Isolate* isolate_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010263 JavaScriptFrame* frame_;
10264 Handle<JSFunction> function_;
10265 Handle<Context> context_;
10266 bool local_done_;
10267 bool at_local_;
10268
10269 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
10270};
10271
10272
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010273RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010274 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010275 ASSERT(args.length() == 2);
10276
10277 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010278 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010279 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10280 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010281 if (!maybe_check->ToObject(&check)) return maybe_check;
10282 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010283 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
10284
10285 // Get the frame where the debugging is performed.
10286 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010287 JavaScriptFrameIterator it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010288 JavaScriptFrame* frame = it.frame();
10289
10290 // Count the visible scopes.
10291 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010292 for (ScopeIterator it(isolate, frame); !it.Done(); it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010293 n++;
10294 }
10295
10296 return Smi::FromInt(n);
10297}
10298
10299
10300static const int kScopeDetailsTypeIndex = 0;
10301static const int kScopeDetailsObjectIndex = 1;
10302static const int kScopeDetailsSize = 2;
10303
10304// Return an array with scope details
10305// args[0]: number: break id
10306// args[1]: number: frame index
10307// args[2]: number: scope index
10308//
10309// The array returned contains the following information:
10310// 0: Scope type
10311// 1: Scope object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010312RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010313 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010314 ASSERT(args.length() == 3);
10315
10316 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010317 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010318 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10319 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010320 if (!maybe_check->ToObject(&check)) return maybe_check;
10321 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010322 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
10323 CONVERT_NUMBER_CHECKED(int, index, Int32, args[2]);
10324
10325 // Get the frame where the debugging is performed.
10326 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010327 JavaScriptFrameIterator frame_it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010328 JavaScriptFrame* frame = frame_it.frame();
10329
10330 // Find the requested scope.
10331 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010332 ScopeIterator it(isolate, frame);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010333 for (; !it.Done() && n < index; it.Next()) {
10334 n++;
10335 }
10336 if (it.Done()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010337 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010338 }
10339
10340 // Calculate the size of the result.
10341 int details_size = kScopeDetailsSize;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010342 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010343
10344 // Fill in scope details.
10345 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010346 Handle<JSObject> scope_object = it.ScopeObject();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010347 RETURN_IF_EMPTY_HANDLE(isolate, scope_object);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010348 details->set(kScopeDetailsObjectIndex, *scope_object);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010349
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010350 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010351}
10352
10353
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010354RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrintScopes) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010355 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010356 ASSERT(args.length() == 0);
10357
10358#ifdef DEBUG
10359 // Print the scopes for the top frame.
10360 StackFrameLocator locator;
10361 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010362 for (ScopeIterator it(isolate, frame); !it.Done(); it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010363 it.DebugPrint();
10364 }
10365#endif
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010366 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010367}
10368
10369
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010370RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010371 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010372 ASSERT(args.length() == 1);
10373
10374 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010375 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010376 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
10377 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010378 if (!maybe_result->ToObject(&result)) return maybe_result;
10379 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010380
10381 // Count all archived V8 threads.
10382 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010383 for (ThreadState* thread =
10384 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010385 thread != NULL;
10386 thread = thread->Next()) {
10387 n++;
10388 }
10389
10390 // Total number of threads is current thread and archived threads.
10391 return Smi::FromInt(n + 1);
10392}
10393
10394
10395static const int kThreadDetailsCurrentThreadIndex = 0;
10396static const int kThreadDetailsThreadIdIndex = 1;
10397static const int kThreadDetailsSize = 2;
10398
10399// Return an array with thread details
10400// args[0]: number: break id
10401// args[1]: number: thread index
10402//
10403// The array returned contains the following information:
10404// 0: Is current thread?
10405// 1: Thread id
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010406RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010407 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010408 ASSERT(args.length() == 2);
10409
10410 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010411 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010412 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10413 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010414 if (!maybe_check->ToObject(&check)) return maybe_check;
10415 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010416 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
10417
10418 // Allocate array for result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010419 Handle<FixedArray> details =
10420 isolate->factory()->NewFixedArray(kThreadDetailsSize);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010421
10422 // Thread index 0 is current thread.
10423 if (index == 0) {
10424 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010425 details->set(kThreadDetailsCurrentThreadIndex,
10426 isolate->heap()->true_value());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010427 details->set(kThreadDetailsThreadIdIndex,
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000010428 Smi::FromInt(ThreadId::Current().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010429 } else {
10430 // Find the thread with the requested index.
10431 int n = 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010432 ThreadState* thread =
10433 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010434 while (index != n && thread != NULL) {
10435 thread = thread->Next();
10436 n++;
10437 }
10438 if (thread == NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010439 return isolate->heap()->undefined_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010440 }
10441
10442 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010443 details->set(kThreadDetailsCurrentThreadIndex,
10444 isolate->heap()->false_value());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000010445 details->set(kThreadDetailsThreadIdIndex,
10446 Smi::FromInt(thread->id().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010447 }
10448
10449 // Convert to JS array and return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010450 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010451}
10452
10453
whesse@chromium.orge90029b2010-08-02 11:52:17 +000010454// Sets the disable break state
10455// args[0]: disable break state
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010456RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDisableBreak) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010457 HandleScope scope(isolate);
whesse@chromium.orge90029b2010-08-02 11:52:17 +000010458 ASSERT(args.length() == 1);
10459 CONVERT_BOOLEAN_CHECKED(disable_break, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010460 isolate->debug()->set_disable_break(disable_break);
10461 return isolate->heap()->undefined_value();
whesse@chromium.orge90029b2010-08-02 11:52:17 +000010462}
10463
10464
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010465RUNTIME_FUNCTION(MaybeObject*, Runtime_GetBreakLocations) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010466 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010467 ASSERT(args.length() == 1);
10468
ager@chromium.org5aa501c2009-06-23 07:57:28 +000010469 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
10470 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010471 // Find the number of break points
10472 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010473 if (break_locations->IsUndefined()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010474 // Return array as JS array
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010475 return *isolate->factory()->NewJSArrayWithElements(
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010476 Handle<FixedArray>::cast(break_locations));
10477}
10478
10479
10480// Set a break point in a function
10481// args[0]: function
10482// args[1]: number: break source position (within the function source)
10483// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010484RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFunctionBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010485 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010486 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +000010487 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
10488 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010489 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
10490 RUNTIME_ASSERT(source_position >= 0);
10491 Handle<Object> break_point_object_arg = args.at<Object>(2);
10492
10493 // Set break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010494 isolate->debug()->SetBreakPoint(shared, break_point_object_arg,
10495 &source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010496
lrn@chromium.org32d961d2010-06-30 09:09:34 +000010497 return Smi::FromInt(source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010498}
10499
10500
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010501Object* Runtime::FindSharedFunctionInfoInScript(Isolate* isolate,
10502 Handle<Script> script,
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000010503 int position) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010504 // Iterate the heap looking for SharedFunctionInfo generated from the
10505 // script. The inner most SharedFunctionInfo containing the source position
10506 // for the requested break point is found.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010507 // NOTE: This might require several heap iterations. If the SharedFunctionInfo
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010508 // which is found is not compiled it is compiled and the heap is iterated
10509 // again as the compilation might create inner functions from the newly
10510 // compiled function and the actual requested break point might be in one of
10511 // these functions.
10512 bool done = false;
10513 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +000010514 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010515 Handle<SharedFunctionInfo> target;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010516 while (!done) {
10517 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010518 for (HeapObject* obj = iterator.next();
10519 obj != NULL; obj = iterator.next()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010520 if (obj->IsSharedFunctionInfo()) {
10521 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
10522 if (shared->script() == *script) {
10523 // If the SharedFunctionInfo found has the requested script data and
10524 // contains the source position it is a candidate.
10525 int start_position = shared->function_token_position();
ager@chromium.org236ad962008-09-25 09:45:57 +000010526 if (start_position == RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010527 start_position = shared->start_position();
10528 }
10529 if (start_position <= position &&
10530 position <= shared->end_position()) {
ager@chromium.org32912102009-01-16 10:38:43 +000010531 // If there is no candidate or this function is within the current
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010532 // candidate this is the new candidate.
10533 if (target.is_null()) {
10534 target_start_position = start_position;
10535 target = shared;
10536 } else {
ager@chromium.orga1645e22009-09-09 19:27:10 +000010537 if (target_start_position == start_position &&
10538 shared->end_position() == target->end_position()) {
10539 // If a top-level function contain only one function
10540 // declartion the source for the top-level and the function is
10541 // the same. In that case prefer the non top-level function.
10542 if (!shared->is_toplevel()) {
10543 target_start_position = start_position;
10544 target = shared;
10545 }
10546 } else if (target_start_position <= start_position &&
10547 shared->end_position() <= target->end_position()) {
10548 // This containment check includes equality as a function inside
10549 // a top-level function can share either start or end position
10550 // with the top-level function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010551 target_start_position = start_position;
10552 target = shared;
10553 }
10554 }
10555 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010556 }
10557 }
10558 }
10559
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010560 if (target.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010561 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010562 }
10563
10564 // If the candidate found is compiled we are done. NOTE: when lazy
10565 // compilation of inner functions is introduced some additional checking
10566 // needs to be done here to compile inner functions.
10567 done = target->is_compiled();
10568 if (!done) {
10569 // If the candidate is not compiled compile it to reveal any inner
10570 // functions which might contain the requested source position.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010571 CompileLazyShared(target, KEEP_EXCEPTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010572 }
10573 }
10574
10575 return *target;
10576}
10577
10578
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000010579// Changes the state of a break point in a script and returns source position
10580// where break point was set. NOTE: Regarding performance see the NOTE for
10581// GetScriptFromScriptData.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010582// args[0]: script to set break point in
10583// args[1]: number: break source position (within the script source)
10584// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010585RUNTIME_FUNCTION(MaybeObject*, Runtime_SetScriptBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010586 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010587 ASSERT(args.length() == 3);
10588 CONVERT_ARG_CHECKED(JSValue, wrapper, 0);
10589 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
10590 RUNTIME_ASSERT(source_position >= 0);
10591 Handle<Object> break_point_object_arg = args.at<Object>(2);
10592
10593 // Get the script from the script wrapper.
10594 RUNTIME_ASSERT(wrapper->value()->IsScript());
10595 Handle<Script> script(Script::cast(wrapper->value()));
10596
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000010597 Object* result = Runtime::FindSharedFunctionInfoInScript(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010598 isolate, script, source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010599 if (!result->IsUndefined()) {
10600 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
10601 // Find position within function. The script position might be before the
10602 // source position of the first function.
10603 int position;
10604 if (shared->start_position() > source_position) {
10605 position = 0;
10606 } else {
10607 position = source_position - shared->start_position();
10608 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010609 isolate->debug()->SetBreakPoint(shared, break_point_object_arg, &position);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000010610 position += shared->start_position();
10611 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010612 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010613 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010614}
10615
10616
10617// Clear a break point
10618// args[0]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010619RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010620 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010621 ASSERT(args.length() == 1);
10622 Handle<Object> break_point_object_arg = args.at<Object>(0);
10623
10624 // Clear break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010625 isolate->debug()->ClearBreakPoint(break_point_object_arg);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010626
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010627 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010628}
10629
10630
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010631// Change the state of break on exceptions.
10632// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
10633// args[1]: Boolean indicating on/off.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010634RUNTIME_FUNCTION(MaybeObject*, Runtime_ChangeBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010635 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010636 ASSERT(args.length() == 2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010637 RUNTIME_ASSERT(args[0]->IsNumber());
10638 CONVERT_BOOLEAN_CHECKED(enable, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010639
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010640 // If the number doesn't match an enum value, the ChangeBreakOnException
10641 // function will default to affecting caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010642 ExceptionBreakType type =
10643 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010644 // Update break point state.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010645 isolate->debug()->ChangeBreakOnException(type, enable);
10646 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010647}
10648
10649
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010650// Returns the state of break on exceptions
10651// args[0]: boolean indicating uncaught exceptions
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010652RUNTIME_FUNCTION(MaybeObject*, Runtime_IsBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010653 HandleScope scope(isolate);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010654 ASSERT(args.length() == 1);
10655 RUNTIME_ASSERT(args[0]->IsNumber());
10656
10657 ExceptionBreakType type =
10658 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010659 bool result = isolate->debug()->IsBreakOnException(type);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010660 return Smi::FromInt(result);
10661}
10662
10663
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010664// Prepare for stepping
10665// args[0]: break id for checking execution state
10666// args[1]: step action from the enumeration StepAction
ager@chromium.orga1645e22009-09-09 19:27:10 +000010667// args[2]: number of times to perform the step, for step out it is the number
10668// of frames to step down.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010669RUNTIME_FUNCTION(MaybeObject*, Runtime_PrepareStep) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010670 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010671 ASSERT(args.length() == 3);
10672 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010673 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010674 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10675 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010676 if (!maybe_check->ToObject(&check)) return maybe_check;
10677 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010678 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010679 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010680 }
10681
10682 // Get the step action and check validity.
10683 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
10684 if (step_action != StepIn &&
10685 step_action != StepNext &&
10686 step_action != StepOut &&
10687 step_action != StepInMin &&
10688 step_action != StepMin) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010689 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010690 }
10691
10692 // Get the number of steps.
10693 int step_count = NumberToInt32(args[2]);
10694 if (step_count < 1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010695 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010696 }
10697
ager@chromium.orga1645e22009-09-09 19:27:10 +000010698 // Clear all current stepping setup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010699 isolate->debug()->ClearStepping();
ager@chromium.orga1645e22009-09-09 19:27:10 +000010700
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010701 // Prepare step.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010702 isolate->debug()->PrepareStep(static_cast<StepAction>(step_action),
10703 step_count);
10704 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010705}
10706
10707
10708// Clear all stepping set by PrepareStep.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010709RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearStepping) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010710 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000010711 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010712 isolate->debug()->ClearStepping();
10713 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010714}
10715
10716
10717// Creates a copy of the with context chain. The copy of the context chain is
10718// is linked to the function context supplied.
10719static Handle<Context> CopyWithContextChain(Handle<Context> context_chain,
10720 Handle<Context> function_context) {
10721 // At the bottom of the chain. Return the function context to link to.
10722 if (context_chain->is_function_context()) {
10723 return function_context;
10724 }
10725
10726 // Recursively copy the with contexts.
10727 Handle<Context> previous(context_chain->previous());
10728 Handle<JSObject> extension(JSObject::cast(context_chain->extension()));
danno@chromium.org160a7b02011-04-18 15:51:38 +000010729 Handle<Context> context = CopyWithContextChain(previous, function_context);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010730 return context->GetIsolate()->factory()->NewWithContext(
10731 context, extension, context_chain->IsCatchContext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010732}
10733
10734
10735// Helper function to find or create the arguments object for
10736// Runtime_DebugEvaluate.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010737static Handle<Object> GetArgumentsObject(Isolate* isolate,
10738 JavaScriptFrame* frame,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010739 Handle<JSFunction> function,
ager@chromium.orgb5737492010-07-15 09:29:43 +000010740 Handle<SerializedScopeInfo> scope_info,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010741 const ScopeInfo<>* sinfo,
10742 Handle<Context> function_context) {
10743 // Try to find the value of 'arguments' to pass as parameter. If it is not
10744 // found (that is the debugged function does not reference 'arguments' and
10745 // does not support eval) then create an 'arguments' object.
10746 int index;
10747 if (sinfo->number_of_stack_slots() > 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010748 index = scope_info->StackSlotIndex(isolate->heap()->arguments_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010749 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010750 return Handle<Object>(frame->GetExpression(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010751 }
10752 }
10753
10754 if (sinfo->number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010755 index = scope_info->ContextSlotIndex(isolate->heap()->arguments_symbol(),
10756 NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010757 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010758 return Handle<Object>(function_context->get(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010759 }
10760 }
10761
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000010762 const int length = frame->ComputeParametersCount();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010763 Handle<JSObject> arguments =
10764 isolate->factory()->NewArgumentsObject(function, length);
10765 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010766
10767 AssertNoAllocation no_gc;
10768 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010769 for (int i = 0; i < length; i++) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010770 array->set(i, frame->GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010771 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000010772 arguments->set_elements(*array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010773 return arguments;
10774}
10775
10776
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010777static const char kSourceStr[] =
10778 "(function(arguments,__source__){return eval(__source__);})";
10779
10780
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010781// Evaluate a piece of JavaScript in the context of a stack frame for
ager@chromium.org32912102009-01-16 10:38:43 +000010782// debugging. This is accomplished by creating a new context which in its
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010783// extension part has all the parameters and locals of the function on the
10784// stack frame. A function which calls eval with the code to evaluate is then
10785// compiled in this context and called in this context. As this context
10786// replaces the context of the function on the stack frame a new (empty)
10787// function is created as well to be used as the closure for the context.
10788// This function and the context acts as replacements for the function on the
10789// stack frame presenting the same view of the values of parameters and
10790// local variables as if the piece of JavaScript was evaluated at the point
10791// where the function on the stack frame is currently stopped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010792RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010793 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010794
10795 // Check the execution state and decode arguments frame and source to be
10796 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010797 ASSERT(args.length() == 5);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010798 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010799 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
10800 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010801 if (!maybe_check_result->ToObject(&check_result)) {
10802 return maybe_check_result;
10803 }
10804 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010805 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
10806 CONVERT_ARG_CHECKED(String, source, 2);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000010807 CONVERT_BOOLEAN_CHECKED(disable_break, args[3]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010808 Handle<Object> additional_context(args[4]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000010809
10810 // Handle the processing of break.
10811 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010812
10813 // Get the frame where the debugging is performed.
10814 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010815 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010816 JavaScriptFrame* frame = it.frame();
10817 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +000010818 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010819 ScopeInfo<> sinfo(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010820
10821 // Traverse the saved contexts chain to find the active context for the
10822 // selected frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010823 SaveContext* save = isolate->save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010824 while (save != NULL && !save->below(frame)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010825 save = save->prev();
10826 }
10827 ASSERT(save != NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010828 SaveContext savex(isolate);
10829 isolate->set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010830
10831 // Create the (empty) function replacing the function on the stack frame for
10832 // the purpose of evaluating in the context created below. It is important
10833 // that this function does not describe any parameters and local variables
10834 // in the context. If it does then this will cause problems with the lookup
10835 // in Context::Lookup, where context slots for parameters and local variables
10836 // are looked at before the extension object.
10837 Handle<JSFunction> go_between =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010838 isolate->factory()->NewFunction(isolate->factory()->empty_string(),
10839 isolate->factory()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010840 go_between->set_context(function->context());
10841#ifdef DEBUG
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010842 ScopeInfo<> go_between_sinfo(go_between->shared()->scope_info());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010843 ASSERT(go_between_sinfo.number_of_parameters() == 0);
10844 ASSERT(go_between_sinfo.number_of_context_slots() == 0);
10845#endif
10846
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010847 // Materialize the content of the local scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010848 Handle<JSObject> local_scope = MaterializeLocalScope(isolate, frame);
10849 RETURN_IF_EMPTY_HANDLE(isolate, local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010850
10851 // Allocate a new context for the debug evaluation and set the extension
10852 // object build.
10853 Handle<Context> context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010854 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
10855 go_between);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010856 context->set_extension(*local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010857 // Copy any with contexts present and chain them in front of this context.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010858 Handle<Context> frame_context(Context::cast(frame->context()));
10859 Handle<Context> function_context(frame_context->fcontext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010860 context = CopyWithContextChain(frame_context, context);
10861
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010862 if (additional_context->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010863 context = isolate->factory()->NewWithContext(context,
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010864 Handle<JSObject>::cast(additional_context), false);
10865 }
10866
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010867 // Wrap the evaluation statement in a new function compiled in the newly
10868 // created context. The function has one parameter which has to be called
10869 // 'arguments'. This it to have access to what would have been 'arguments' in
ager@chromium.org32912102009-01-16 10:38:43 +000010870 // the function being debugged.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010871 // function(arguments,__source__) {return eval(__source__);}
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010872
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010873 Handle<String> function_source =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010874 isolate->factory()->NewStringFromAscii(
10875 Vector<const char>(kSourceStr, sizeof(kSourceStr) - 1));
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010876
10877 // Currently, the eval code will be executed in non-strict mode,
10878 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010879 Handle<SharedFunctionInfo> shared =
ager@chromium.org381abbb2009-02-25 13:23:22 +000010880 Compiler::CompileEval(function_source,
10881 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010882 context->IsGlobalContext(),
10883 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010884 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010885 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010886 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010887
10888 // Invoke the result of the compilation to get the evaluation function.
10889 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010890 Handle<Object> receiver(frame->receiver(), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010891 Handle<Object> evaluation_function =
10892 Execution::Call(compiled_function, receiver, 0, NULL,
10893 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000010894 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010895
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010896 Handle<Object> arguments = GetArgumentsObject(isolate, frame,
10897 function, scope_info,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010898 &sinfo, function_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010899
10900 // Invoke the evaluation function and return the result.
10901 const int argc = 2;
10902 Object** argv[argc] = { arguments.location(),
10903 Handle<Object>::cast(source).location() };
10904 Handle<Object> result =
10905 Execution::Call(Handle<JSFunction>::cast(evaluation_function), receiver,
10906 argc, argv, &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000010907 if (has_pending_exception) return Failure::Exception();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010908
10909 // Skip the global proxy as it has no properties and always delegates to the
10910 // real global object.
10911 if (result->IsJSGlobalProxy()) {
10912 result = Handle<JSObject>(JSObject::cast(result->GetPrototype()));
10913 }
10914
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010915 return *result;
10916}
10917
10918
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010919RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluateGlobal) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010920 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010921
10922 // Check the execution state and decode arguments frame and source to be
10923 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010924 ASSERT(args.length() == 4);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010925 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010926 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
10927 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010928 if (!maybe_check_result->ToObject(&check_result)) {
10929 return maybe_check_result;
10930 }
10931 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010932 CONVERT_ARG_CHECKED(String, source, 1);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000010933 CONVERT_BOOLEAN_CHECKED(disable_break, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010934 Handle<Object> additional_context(args[3]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000010935
10936 // Handle the processing of break.
10937 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010938
10939 // Enter the top context from before the debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010940 SaveContext save(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010941 SaveContext* top = &save;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010942 while (top != NULL && *top->context() == *isolate->debug()->debug_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010943 top = top->prev();
10944 }
10945 if (top != NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010946 isolate->set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010947 }
10948
10949 // Get the global context now set to the top context from before the
10950 // debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010951 Handle<Context> context = isolate->global_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010952
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010953 bool is_global = true;
10954
10955 if (additional_context->IsJSObject()) {
10956 // Create a function context first, than put 'with' context on top of it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010957 Handle<JSFunction> go_between = isolate->factory()->NewFunction(
10958 isolate->factory()->empty_string(),
10959 isolate->factory()->undefined_value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010960 go_between->set_context(*context);
10961 context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010962 isolate->factory()->NewFunctionContext(
10963 Context::MIN_CONTEXT_SLOTS, go_between);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010964 context->set_extension(JSObject::cast(*additional_context));
10965 is_global = false;
10966 }
10967
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010968 // Compile the source to be evaluated.
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010969 // Currently, the eval code will be executed in non-strict mode,
10970 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010971 Handle<SharedFunctionInfo> shared =
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010972 Compiler::CompileEval(source, context, is_global, kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010973 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010974 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010975 Handle<JSFunction>(
10976 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
10977 context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010978
10979 // Invoke the result of the compilation to get the evaluation function.
10980 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010981 Handle<Object> receiver = isolate->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010982 Handle<Object> result =
10983 Execution::Call(compiled_function, receiver, 0, NULL,
10984 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000010985 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010986 return *result;
10987}
10988
10989
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010990RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetLoadedScripts) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010991 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000010992 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010993
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010994 // Fill the script objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010995 Handle<FixedArray> instances = isolate->debug()->GetLoadedScripts();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010996
10997 // Convert the script objects to proper JS objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +000010998 for (int i = 0; i < instances->length(); i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +000010999 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
11000 // Get the script wrapper in a local handle before calling GetScriptWrapper,
11001 // because using
11002 // instances->set(i, *GetScriptWrapper(script))
11003 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
11004 // already have deferenced the instances handle.
11005 Handle<JSValue> wrapper = GetScriptWrapper(script);
11006 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011007 }
11008
11009 // Return result as a JS array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011010 Handle<JSObject> result =
11011 isolate->factory()->NewJSObject(isolate->array_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011012 Handle<JSArray>::cast(result)->SetContent(*instances);
11013 return *result;
11014}
11015
11016
11017// Helper function used by Runtime_DebugReferencedBy below.
11018static int DebugReferencedBy(JSObject* target,
11019 Object* instance_filter, int max_references,
11020 FixedArray* instances, int instances_size,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011021 JSFunction* arguments_function) {
11022 NoHandleAllocation ha;
11023 AssertNoAllocation no_alloc;
11024
11025 // Iterate the heap.
11026 int count = 0;
11027 JSObject* last = NULL;
11028 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011029 HeapObject* heap_obj = NULL;
11030 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011031 (max_references == 0 || count < max_references)) {
11032 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011033 if (heap_obj->IsJSObject()) {
11034 // Skip context extension objects and argument arrays as these are
11035 // checked in the context of functions using them.
11036 JSObject* obj = JSObject::cast(heap_obj);
iposva@chromium.org245aa852009-02-10 00:49:54 +000011037 if (obj->IsJSContextExtensionObject() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011038 obj->map()->constructor() == arguments_function) {
11039 continue;
11040 }
11041
11042 // Check if the JS object has a reference to the object looked for.
11043 if (obj->ReferencesObject(target)) {
11044 // Check instance filter if supplied. This is normally used to avoid
11045 // references from mirror objects (see Runtime_IsInPrototypeChain).
11046 if (!instance_filter->IsUndefined()) {
11047 Object* V = obj;
11048 while (true) {
11049 Object* prototype = V->GetPrototype();
11050 if (prototype->IsNull()) {
11051 break;
11052 }
11053 if (instance_filter == prototype) {
11054 obj = NULL; // Don't add this object.
11055 break;
11056 }
11057 V = prototype;
11058 }
11059 }
11060
11061 if (obj != NULL) {
11062 // Valid reference found add to instance array if supplied an update
11063 // count.
11064 if (instances != NULL && count < instances_size) {
11065 instances->set(count, obj);
11066 }
11067 last = obj;
11068 count++;
11069 }
11070 }
11071 }
11072 }
11073
11074 // Check for circular reference only. This can happen when the object is only
11075 // referenced from mirrors and has a circular reference in which case the
11076 // object is not really alive and would have been garbage collected if not
11077 // referenced from the mirror.
11078 if (count == 1 && last == target) {
11079 count = 0;
11080 }
11081
11082 // Return the number of referencing objects found.
11083 return count;
11084}
11085
11086
11087// Scan the heap for objects with direct references to an object
11088// args[0]: the object to find references to
11089// args[1]: constructor function for instances to exclude (Mirror)
11090// args[2]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011091RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugReferencedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011092 ASSERT(args.length() == 3);
11093
11094 // First perform a full GC in order to avoid references from dead objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011095 isolate->heap()->CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011096
11097 // Check parameters.
11098 CONVERT_CHECKED(JSObject, target, args[0]);
11099 Object* instance_filter = args[1];
11100 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
11101 instance_filter->IsJSObject());
11102 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
11103 RUNTIME_ASSERT(max_references >= 0);
11104
11105 // Get the constructor function for context extension and arguments array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011106 JSObject* arguments_boilerplate =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011107 isolate->context()->global_context()->arguments_boilerplate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011108 JSFunction* arguments_function =
11109 JSFunction::cast(arguments_boilerplate->map()->constructor());
11110
11111 // Get the number of referencing objects.
11112 int count;
11113 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000011114 NULL, 0, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011115
11116 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011117 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011118 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011119 if (!maybe_object->ToObject(&object)) return maybe_object;
11120 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011121 FixedArray* instances = FixedArray::cast(object);
11122
11123 // Fill the referencing objects.
11124 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000011125 instances, count, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011126
11127 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011128 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011129 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
11130 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011131 if (!maybe_result->ToObject(&result)) return maybe_result;
11132 }
11133 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011134 return result;
11135}
11136
11137
11138// Helper function used by Runtime_DebugConstructedBy below.
11139static int DebugConstructedBy(JSFunction* constructor, int max_references,
11140 FixedArray* instances, int instances_size) {
11141 AssertNoAllocation no_alloc;
11142
11143 // Iterate the heap.
11144 int count = 0;
11145 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011146 HeapObject* heap_obj = NULL;
11147 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011148 (max_references == 0 || count < max_references)) {
11149 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011150 if (heap_obj->IsJSObject()) {
11151 JSObject* obj = JSObject::cast(heap_obj);
11152 if (obj->map()->constructor() == constructor) {
11153 // Valid reference found add to instance array if supplied an update
11154 // count.
11155 if (instances != NULL && count < instances_size) {
11156 instances->set(count, obj);
11157 }
11158 count++;
11159 }
11160 }
11161 }
11162
11163 // Return the number of referencing objects found.
11164 return count;
11165}
11166
11167
11168// Scan the heap for objects constructed by a specific function.
11169// args[0]: the constructor to find instances of
11170// args[1]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011171RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugConstructedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011172 ASSERT(args.length() == 2);
11173
11174 // First perform a full GC in order to avoid dead objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011175 isolate->heap()->CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011176
11177 // Check parameters.
11178 CONVERT_CHECKED(JSFunction, constructor, args[0]);
11179 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
11180 RUNTIME_ASSERT(max_references >= 0);
11181
11182 // Get the number of referencing objects.
11183 int count;
11184 count = DebugConstructedBy(constructor, max_references, NULL, 0);
11185
11186 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011187 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011188 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011189 if (!maybe_object->ToObject(&object)) return maybe_object;
11190 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011191 FixedArray* instances = FixedArray::cast(object);
11192
11193 // Fill the referencing objects.
11194 count = DebugConstructedBy(constructor, max_references, instances, count);
11195
11196 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011197 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011198 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
11199 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011200 if (!maybe_result->ToObject(&result)) return maybe_result;
11201 }
11202 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011203 return result;
11204}
11205
11206
ager@chromium.orgddb913d2009-01-27 10:01:48 +000011207// Find the effective prototype object as returned by __proto__.
11208// args[0]: the object to find the prototype for.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011209RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPrototype) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011210 ASSERT(args.length() == 1);
11211
11212 CONVERT_CHECKED(JSObject, obj, args[0]);
11213
ager@chromium.orgddb913d2009-01-27 10:01:48 +000011214 // Use the __proto__ accessor.
11215 return Accessors::ObjectPrototype.getter(obj, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011216}
11217
11218
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011219RUNTIME_FUNCTION(MaybeObject*, Runtime_SystemBreak) {
mads.s.ager31e71382008-08-13 09:32:07 +000011220 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011221 CPU::DebugBreak();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011222 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011223}
11224
11225
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011226RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleFunction) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011227#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011228 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011229 ASSERT(args.length() == 1);
11230 // Get the function and make sure it is compiled.
11231 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011232 Handle<SharedFunctionInfo> shared(func->shared());
11233 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011234 return Failure::Exception();
11235 }
11236 func->code()->PrintLn();
11237#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011238 return isolate->heap()->undefined_value();
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011239}
ager@chromium.org9085a012009-05-11 19:22:57 +000011240
11241
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011242RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleConstructor) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011243#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011244 HandleScope scope(isolate);
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011245 ASSERT(args.length() == 1);
11246 // Get the function and make sure it is compiled.
11247 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011248 Handle<SharedFunctionInfo> shared(func->shared());
11249 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011250 return Failure::Exception();
11251 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011252 shared->construct_stub()->PrintLn();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011253#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011254 return isolate->heap()->undefined_value();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011255}
11256
11257
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011258RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetInferredName) {
ager@chromium.org9085a012009-05-11 19:22:57 +000011259 NoHandleAllocation ha;
11260 ASSERT(args.length() == 1);
11261
11262 CONVERT_CHECKED(JSFunction, f, args[0]);
11263 return f->shared()->inferred_name();
11264}
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011265
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011266
11267static int FindSharedFunctionInfosForScript(Script* script,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011268 FixedArray* buffer) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011269 AssertNoAllocation no_allocations;
11270
11271 int counter = 0;
11272 int buffer_size = buffer->length();
11273 HeapIterator iterator;
11274 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
11275 ASSERT(obj != NULL);
11276 if (!obj->IsSharedFunctionInfo()) {
11277 continue;
11278 }
11279 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
11280 if (shared->script() != script) {
11281 continue;
11282 }
11283 if (counter < buffer_size) {
11284 buffer->set(counter, shared);
11285 }
11286 counter++;
11287 }
11288 return counter;
11289}
11290
11291// For a script finds all SharedFunctionInfo's in the heap that points
11292// to this script. Returns JSArray of SharedFunctionInfo wrapped
11293// in OpaqueReferences.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011294RUNTIME_FUNCTION(MaybeObject*,
11295 Runtime_LiveEditFindSharedFunctionInfosForScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011296 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011297 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011298 CONVERT_CHECKED(JSValue, script_value, args[0]);
11299
11300 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
11301
11302 const int kBufferSize = 32;
11303
11304 Handle<FixedArray> array;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011305 array = isolate->factory()->NewFixedArray(kBufferSize);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011306 int number = FindSharedFunctionInfosForScript(*script, *array);
11307 if (number > kBufferSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011308 array = isolate->factory()->NewFixedArray(number);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011309 FindSharedFunctionInfosForScript(*script, *array);
11310 }
11311
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011312 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011313 result->set_length(Smi::FromInt(number));
11314
11315 LiveEdit::WrapSharedFunctionInfos(result);
11316
11317 return *result;
11318}
11319
11320// For a script calculates compilation information about all its functions.
11321// The script source is explicitly specified by the second argument.
11322// The source of the actual script is not used, however it is important that
11323// all generated code keeps references to this particular instance of script.
11324// Returns a JSArray of compilation infos. The array is ordered so that
11325// each function with all its descendant is always stored in a continues range
11326// with the function itself going first. The root function is a script function.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011327RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditGatherCompileInfo) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011328 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011329 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011330 CONVERT_CHECKED(JSValue, script, args[0]);
11331 CONVERT_ARG_CHECKED(String, source, 1);
11332 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
11333
11334 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
11335
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011336 if (isolate->has_pending_exception()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011337 return Failure::Exception();
11338 }
11339
11340 return result;
11341}
11342
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011343// Changes the source of the script to a new_source.
11344// If old_script_name is provided (i.e. is a String), also creates a copy of
11345// the script with its original source and sends notification to debugger.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011346RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011347 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011348 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011349 CONVERT_CHECKED(JSValue, original_script_value, args[0]);
11350 CONVERT_ARG_CHECKED(String, new_source, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011351 Handle<Object> old_script_name(args[2], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011352
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011353 CONVERT_CHECKED(Script, original_script_pointer,
11354 original_script_value->value());
11355 Handle<Script> original_script(original_script_pointer);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011356
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011357 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
11358 new_source,
11359 old_script_name);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011360
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011361 if (old_script->IsScript()) {
11362 Handle<Script> script_handle(Script::cast(old_script));
11363 return *(GetScriptWrapper(script_handle));
11364 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011365 return isolate->heap()->null_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011366 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011367}
11368
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011369
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011370RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSourceUpdated) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011371 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011372 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011373 CONVERT_ARG_CHECKED(JSArray, shared_info, 0);
11374 return LiveEdit::FunctionSourceUpdated(shared_info);
11375}
11376
11377
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011378// Replaces code of SharedFunctionInfo with a new one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011379RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceFunctionCode) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011380 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011381 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011382 CONVERT_ARG_CHECKED(JSArray, new_compile_info, 0);
11383 CONVERT_ARG_CHECKED(JSArray, shared_info, 1);
11384
ager@chromium.orgac091b72010-05-05 07:34:42 +000011385 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011386}
11387
11388// Connects SharedFunctionInfo to another script.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011389RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSetScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011390 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011391 HandleScope scope(isolate);
11392 Handle<Object> function_object(args[0], isolate);
11393 Handle<Object> script_object(args[1], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011394
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011395 if (function_object->IsJSValue()) {
11396 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
11397 if (script_object->IsJSValue()) {
11398 CONVERT_CHECKED(Script, script, JSValue::cast(*script_object)->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011399 script_object = Handle<Object>(script, isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011400 }
11401
11402 LiveEdit::SetFunctionScript(function_wrapper, script_object);
11403 } else {
11404 // Just ignore this. We may not have a SharedFunctionInfo for some functions
11405 // and we check it in this function.
11406 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011407
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011408 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011409}
11410
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011411
11412// In a code of a parent function replaces original function as embedded object
11413// with a substitution one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011414RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceRefToNestedFunction) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011415 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011416 HandleScope scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011417
11418 CONVERT_ARG_CHECKED(JSValue, parent_wrapper, 0);
11419 CONVERT_ARG_CHECKED(JSValue, orig_wrapper, 1);
11420 CONVERT_ARG_CHECKED(JSValue, subst_wrapper, 2);
11421
11422 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
11423 subst_wrapper);
11424
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011425 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011426}
11427
11428
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011429// Updates positions of a shared function info (first parameter) according
11430// to script source change. Text change is described in second parameter as
11431// array of groups of 3 numbers:
11432// (change_begin, change_end, change_end_new_position).
11433// Each group describes a change in text; groups are sorted by change_begin.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011434RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditPatchFunctionPositions) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011435 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011436 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011437 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
11438 CONVERT_ARG_CHECKED(JSArray, position_change_array, 1);
11439
ager@chromium.orgac091b72010-05-05 07:34:42 +000011440 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011441}
11442
11443
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011444// For array of SharedFunctionInfo's (each wrapped in JSValue)
11445// checks that none of them have activations on stacks (of any thread).
11446// Returns array of the same length with corresponding results of
11447// LiveEdit::FunctionPatchabilityStatus type.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011448RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCheckAndDropActivations) {
ager@chromium.org357bf652010-04-12 11:30:10 +000011449 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011450 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011451 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
ager@chromium.org357bf652010-04-12 11:30:10 +000011452 CONVERT_BOOLEAN_CHECKED(do_drop, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011453
ager@chromium.org357bf652010-04-12 11:30:10 +000011454 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011455}
11456
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000011457// Compares 2 strings line-by-line, then token-wise and returns diff in form
11458// of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
11459// of diff chunks.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011460RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCompareStrings) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011461 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011462 HandleScope scope(isolate);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011463 CONVERT_ARG_CHECKED(String, s1, 0);
11464 CONVERT_ARG_CHECKED(String, s2, 1);
11465
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000011466 return *LiveEdit::CompareStrings(s1, s2);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011467}
11468
11469
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011470// A testing entry. Returns statement position which is the closest to
11471// source_position.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011472RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionCodePositionFromSource) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011473 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011474 HandleScope scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011475 CONVERT_ARG_CHECKED(JSFunction, function, 0);
11476 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11477
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011478 Handle<Code> code(function->code(), isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011479
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011480 if (code->kind() != Code::FUNCTION &&
11481 code->kind() != Code::OPTIMIZED_FUNCTION) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011482 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011483 }
11484
11485 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011486 int closest_pc = 0;
11487 int distance = kMaxInt;
11488 while (!it.done()) {
11489 int statement_position = static_cast<int>(it.rinfo()->data());
11490 // Check if this break point is closer that what was previously found.
11491 if (source_position <= statement_position &&
11492 statement_position - source_position < distance) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +000011493 closest_pc =
11494 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011495 distance = statement_position - source_position;
11496 // Check whether we can't get any closer.
11497 if (distance == 0) break;
11498 }
11499 it.next();
11500 }
11501
11502 return Smi::FromInt(closest_pc);
11503}
11504
11505
ager@chromium.org357bf652010-04-12 11:30:10 +000011506// Calls specified function with or without entering the debugger.
11507// This is used in unit tests to run code as if debugger is entered or simply
11508// to have a stack with C++ frame in the middle.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011509RUNTIME_FUNCTION(MaybeObject*, Runtime_ExecuteInDebugContext) {
ager@chromium.org357bf652010-04-12 11:30:10 +000011510 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011511 HandleScope scope(isolate);
ager@chromium.org357bf652010-04-12 11:30:10 +000011512 CONVERT_ARG_CHECKED(JSFunction, function, 0);
11513 CONVERT_BOOLEAN_CHECKED(without_debugger, args[1]);
11514
11515 Handle<Object> result;
11516 bool pending_exception;
11517 {
11518 if (without_debugger) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011519 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000011520 &pending_exception);
11521 } else {
11522 EnterDebugger enter_debugger;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011523 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000011524 &pending_exception);
11525 }
11526 }
11527 if (!pending_exception) {
11528 return *result;
11529 } else {
11530 return Failure::Exception();
11531 }
11532}
11533
11534
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011535// Sets a v8 flag.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011536RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFlags) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011537 CONVERT_CHECKED(String, arg, args[0]);
11538 SmartPointer<char> flags =
11539 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
11540 FlagList::SetFlagsFromString(*flags, StrLength(*flags));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011541 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011542}
11543
11544
11545// Performs a GC.
11546// Presently, it only does a full GC.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011547RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectGarbage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011548 isolate->heap()->CollectAllGarbage(true);
11549 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011550}
11551
11552
11553// Gets the current heap usage.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011554RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHeapUsage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011555 int usage = static_cast<int>(isolate->heap()->SizeOfObjects());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011556 if (!Smi::IsValid(usage)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011557 return *isolate->factory()->NewNumberFromInt(usage);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011558 }
11559 return Smi::FromInt(usage);
11560}
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011561
11562
11563// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011564RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLOLEnabled) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011565#ifdef LIVE_OBJECT_LIST
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011566 return isolate->heap()->true_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011567#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011568 return isolate->heap()->false_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011569#endif
11570}
11571
11572
11573// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011574RUNTIME_FUNCTION(MaybeObject*, Runtime_CaptureLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011575#ifdef LIVE_OBJECT_LIST
11576 return LiveObjectList::Capture();
11577#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011578 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011579#endif
11580}
11581
11582
11583// Deletes the specified live object list.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011584RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011585#ifdef LIVE_OBJECT_LIST
11586 CONVERT_SMI_CHECKED(id, args[0]);
11587 bool success = LiveObjectList::Delete(id);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011588 return success ? isolate->heap()->true_value() :
11589 isolate->heap()->false_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011590#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011591 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011592#endif
11593}
11594
11595
11596// Generates the response to a debugger request for a dump of the objects
11597// contained in the difference between the captured live object lists
11598// specified by id1 and id2.
11599// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
11600// dumped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011601RUNTIME_FUNCTION(MaybeObject*, Runtime_DumpLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011602#ifdef LIVE_OBJECT_LIST
11603 HandleScope scope;
11604 CONVERT_SMI_CHECKED(id1, args[0]);
11605 CONVERT_SMI_CHECKED(id2, args[1]);
11606 CONVERT_SMI_CHECKED(start, args[2]);
11607 CONVERT_SMI_CHECKED(count, args[3]);
11608 CONVERT_ARG_CHECKED(JSObject, filter_obj, 4);
11609 EnterDebugger enter_debugger;
11610 return LiveObjectList::Dump(id1, id2, start, count, filter_obj);
11611#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011612 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011613#endif
11614}
11615
11616
11617// Gets the specified object as requested by the debugger.
11618// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011619RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011620#ifdef LIVE_OBJECT_LIST
11621 CONVERT_SMI_CHECKED(obj_id, args[0]);
11622 Object* result = LiveObjectList::GetObj(obj_id);
11623 return result;
11624#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011625 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011626#endif
11627}
11628
11629
11630// Gets the obj id for the specified address if valid.
11631// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011632RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjId) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011633#ifdef LIVE_OBJECT_LIST
11634 HandleScope scope;
11635 CONVERT_ARG_CHECKED(String, address, 0);
11636 Object* result = LiveObjectList::GetObjId(address);
11637 return result;
11638#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011639 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011640#endif
11641}
11642
11643
11644// Gets the retainers that references the specified object alive.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011645RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjRetainers) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011646#ifdef LIVE_OBJECT_LIST
11647 HandleScope scope;
11648 CONVERT_SMI_CHECKED(obj_id, args[0]);
11649 RUNTIME_ASSERT(args[1]->IsUndefined() || args[1]->IsJSObject());
11650 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsBoolean());
11651 RUNTIME_ASSERT(args[3]->IsUndefined() || args[3]->IsSmi());
11652 RUNTIME_ASSERT(args[4]->IsUndefined() || args[4]->IsSmi());
11653 CONVERT_ARG_CHECKED(JSObject, filter_obj, 5);
11654
11655 Handle<JSObject> instance_filter;
11656 if (args[1]->IsJSObject()) {
11657 instance_filter = args.at<JSObject>(1);
11658 }
11659 bool verbose = false;
11660 if (args[2]->IsBoolean()) {
11661 verbose = args[2]->IsTrue();
11662 }
11663 int start = 0;
11664 if (args[3]->IsSmi()) {
11665 start = Smi::cast(args[3])->value();
11666 }
11667 int limit = Smi::kMaxValue;
11668 if (args[4]->IsSmi()) {
11669 limit = Smi::cast(args[4])->value();
11670 }
11671
11672 return LiveObjectList::GetObjRetainers(obj_id,
11673 instance_filter,
11674 verbose,
11675 start,
11676 limit,
11677 filter_obj);
11678#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011679 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011680#endif
11681}
11682
11683
11684// Gets the reference path between 2 objects.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011685RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLPath) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011686#ifdef LIVE_OBJECT_LIST
11687 HandleScope scope;
11688 CONVERT_SMI_CHECKED(obj_id1, args[0]);
11689 CONVERT_SMI_CHECKED(obj_id2, args[1]);
11690 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsJSObject());
11691
11692 Handle<JSObject> instance_filter;
11693 if (args[2]->IsJSObject()) {
11694 instance_filter = args.at<JSObject>(2);
11695 }
11696
11697 Object* result =
11698 LiveObjectList::GetPath(obj_id1, obj_id2, instance_filter);
11699 return result;
11700#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011701 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011702#endif
11703}
11704
11705
11706// Generates the response to a debugger request for a list of all
11707// previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011708RUNTIME_FUNCTION(MaybeObject*, Runtime_InfoLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011709#ifdef LIVE_OBJECT_LIST
11710 CONVERT_SMI_CHECKED(start, args[0]);
11711 CONVERT_SMI_CHECKED(count, args[1]);
11712 return LiveObjectList::Info(start, count);
11713#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011714 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011715#endif
11716}
11717
11718
11719// Gets a dump of the specified object as requested by the debugger.
11720// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011721RUNTIME_FUNCTION(MaybeObject*, Runtime_PrintLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011722#ifdef LIVE_OBJECT_LIST
11723 HandleScope scope;
11724 CONVERT_SMI_CHECKED(obj_id, args[0]);
11725 Object* result = LiveObjectList::PrintObj(obj_id);
11726 return result;
11727#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011728 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011729#endif
11730}
11731
11732
11733// Resets and releases all previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011734RUNTIME_FUNCTION(MaybeObject*, Runtime_ResetLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011735#ifdef LIVE_OBJECT_LIST
11736 LiveObjectList::Reset();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011737 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011738#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011739 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011740#endif
11741}
11742
11743
11744// Generates the response to a debugger request for a summary of the types
11745// of objects in the difference between the captured live object lists
11746// specified by id1 and id2.
11747// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
11748// summarized.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011749RUNTIME_FUNCTION(MaybeObject*, Runtime_SummarizeLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011750#ifdef LIVE_OBJECT_LIST
11751 HandleScope scope;
11752 CONVERT_SMI_CHECKED(id1, args[0]);
11753 CONVERT_SMI_CHECKED(id2, args[1]);
11754 CONVERT_ARG_CHECKED(JSObject, filter_obj, 2);
11755
11756 EnterDebugger enter_debugger;
11757 return LiveObjectList::Summarize(id1, id2, filter_obj);
11758#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011759 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011760#endif
11761}
11762
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011763#endif // ENABLE_DEBUGGER_SUPPORT
11764
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011765
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011766#ifdef ENABLE_LOGGING_AND_PROFILING
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011767RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerResume) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011768 NoHandleAllocation ha;
ager@chromium.org5c838252010-02-19 08:53:10 +000011769 ASSERT(args.length() == 2);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011770
11771 CONVERT_CHECKED(Smi, smi_modules, args[0]);
ager@chromium.org5c838252010-02-19 08:53:10 +000011772 CONVERT_CHECKED(Smi, smi_tag, args[1]);
11773 v8::V8::ResumeProfilerEx(smi_modules->value(), smi_tag->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011774 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011775}
11776
11777
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011778RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerPause) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011779 NoHandleAllocation ha;
ager@chromium.org5c838252010-02-19 08:53:10 +000011780 ASSERT(args.length() == 2);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011781
11782 CONVERT_CHECKED(Smi, smi_modules, args[0]);
ager@chromium.org5c838252010-02-19 08:53:10 +000011783 CONVERT_CHECKED(Smi, smi_tag, args[1]);
11784 v8::V8::PauseProfilerEx(smi_modules->value(), smi_tag->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011785 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011786}
11787
11788#endif // ENABLE_LOGGING_AND_PROFILING
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011789
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011790// Finds the script object from the script data. NOTE: This operation uses
11791// heap traversal to find the function generated for the source position
11792// for the requested break point. For lazily compiled functions several heap
11793// traversals might be required rendering this operation as a rather slow
11794// operation. However for setting break points which is normally done through
11795// some kind of user interaction the performance is not crucial.
11796static Handle<Object> Runtime_GetScriptFromScriptName(
11797 Handle<String> script_name) {
11798 // Scan the heap for Script objects to find the script with the requested
11799 // script data.
11800 Handle<Script> script;
11801 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011802 HeapObject* obj = NULL;
11803 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011804 // If a script is found check if it has the script data requested.
11805 if (obj->IsScript()) {
11806 if (Script::cast(obj)->name()->IsString()) {
11807 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
11808 script = Handle<Script>(Script::cast(obj));
11809 }
11810 }
11811 }
11812 }
11813
11814 // If no script with the requested script data is found return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011815 if (script.is_null()) return FACTORY->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011816
11817 // Return the script found.
11818 return GetScriptWrapper(script);
11819}
11820
11821
11822// Get the script object from script data. NOTE: Regarding performance
11823// see the NOTE for GetScriptFromScriptData.
11824// args[0]: script data for the script to find the source for
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011825RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011826 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011827
11828 ASSERT(args.length() == 1);
11829
11830 CONVERT_CHECKED(String, script_name, args[0]);
11831
11832 // Find the requested script.
11833 Handle<Object> result =
11834 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
11835 return *result;
11836}
11837
11838
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011839// Determines whether the given stack frame should be displayed in
11840// a stack trace. The caller is the error constructor that asked
11841// for the stack trace to be collected. The first time a construct
11842// call to this function is encountered it is skipped. The seen_caller
11843// in/out parameter is used to remember if the caller has been seen
11844// yet.
11845static bool ShowFrameInStackTrace(StackFrame* raw_frame, Object* caller,
11846 bool* seen_caller) {
11847 // Only display JS frames.
11848 if (!raw_frame->is_java_script())
11849 return false;
11850 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
11851 Object* raw_fun = frame->function();
11852 // Not sure when this can happen but skip it just in case.
11853 if (!raw_fun->IsJSFunction())
11854 return false;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011855 if ((raw_fun == caller) && !(*seen_caller)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011856 *seen_caller = true;
11857 return false;
11858 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011859 // Skip all frames until we've seen the caller. Also, skip the most
11860 // obvious builtin calls. Some builtin calls (such as Number.ADD
11861 // which is invoked using 'call') are very difficult to recognize
11862 // so we're leaving them in for now.
11863 return *seen_caller && !frame->receiver()->IsJSBuiltinsObject();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011864}
11865
11866
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011867// Collect the raw data for a stack trace. Returns an array of 4
11868// element segments each containing a receiver, function, code and
11869// native code offset.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011870RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectStackTrace) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011871 ASSERT_EQ(args.length(), 2);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011872 Handle<Object> caller = args.at<Object>(0);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011873 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[1]);
11874
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011875 HandleScope scope(isolate);
11876 Factory* factory = isolate->factory();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011877
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000011878 limit = Max(limit, 0); // Ensure that limit is not negative.
11879 int initial_size = Min(limit, 10);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011880 Handle<FixedArray> elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011881 factory->NewFixedArrayWithHoles(initial_size * 4);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011882
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011883 StackFrameIterator iter(isolate);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011884 // If the caller parameter is a function we skip frames until we're
11885 // under it before starting to collect.
11886 bool seen_caller = !caller->IsJSFunction();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011887 int cursor = 0;
11888 int frames_seen = 0;
11889 while (!iter.done() && frames_seen < limit) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011890 StackFrame* raw_frame = iter.frame();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011891 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011892 frames_seen++;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011893 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011894 // Set initial size to the maximum inlining level + 1 for the outermost
11895 // function.
11896 List<FrameSummary> frames(Compiler::kMaxInliningLevels + 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011897 frame->Summarize(&frames);
11898 for (int i = frames.length() - 1; i >= 0; i--) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011899 if (cursor + 4 > elements->length()) {
11900 int new_capacity = JSObject::NewElementsCapacity(elements->length());
11901 Handle<FixedArray> new_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011902 factory->NewFixedArrayWithHoles(new_capacity);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011903 for (int i = 0; i < cursor; i++) {
11904 new_elements->set(i, elements->get(i));
11905 }
11906 elements = new_elements;
11907 }
11908 ASSERT(cursor + 4 <= elements->length());
11909
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011910 Handle<Object> recv = frames[i].receiver();
11911 Handle<JSFunction> fun = frames[i].function();
11912 Handle<Code> code = frames[i].code();
11913 Handle<Smi> offset(Smi::FromInt(frames[i].offset()));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011914 elements->set(cursor++, *recv);
11915 elements->set(cursor++, *fun);
11916 elements->set(cursor++, *code);
11917 elements->set(cursor++, *offset);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011918 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011919 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011920 iter.Advance();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011921 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011922 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011923 result->set_length(Smi::FromInt(cursor));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011924 return *result;
11925}
11926
11927
ager@chromium.org3811b432009-10-28 14:53:37 +000011928// Returns V8 version as a string.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011929RUNTIME_FUNCTION(MaybeObject*, Runtime_GetV8Version) {
ager@chromium.org3811b432009-10-28 14:53:37 +000011930 ASSERT_EQ(args.length(), 0);
11931
11932 NoHandleAllocation ha;
11933
11934 const char* version_string = v8::V8::GetVersion();
11935
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011936 return isolate->heap()->AllocateStringFromAscii(CStrVector(version_string),
11937 NOT_TENURED);
ager@chromium.org3811b432009-10-28 14:53:37 +000011938}
11939
11940
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011941RUNTIME_FUNCTION(MaybeObject*, Runtime_Abort) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011942 ASSERT(args.length() == 2);
11943 OS::PrintError("abort: %s\n", reinterpret_cast<char*>(args[0]) +
11944 Smi::cast(args[1])->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011945 isolate->PrintStack();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011946 OS::Abort();
11947 UNREACHABLE();
11948 return NULL;
11949}
11950
11951
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011952RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFromCache) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011953 // This is only called from codegen, so checks might be more lax.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011954 CONVERT_CHECKED(JSFunctionResultCache, cache, args[0]);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011955 Object* key = args[1];
11956
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011957 int finger_index = cache->finger_index();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011958 Object* o = cache->get(finger_index);
11959 if (o == key) {
11960 // The fastest case: hit the same place again.
11961 return cache->get(finger_index + 1);
11962 }
11963
11964 for (int i = finger_index - 2;
11965 i >= JSFunctionResultCache::kEntriesIndex;
11966 i -= 2) {
11967 o = cache->get(i);
11968 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011969 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011970 return cache->get(i + 1);
11971 }
11972 }
11973
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011974 int size = cache->size();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011975 ASSERT(size <= cache->length());
11976
11977 for (int i = size - 2; i > finger_index; i -= 2) {
11978 o = cache->get(i);
11979 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011980 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011981 return cache->get(i + 1);
11982 }
11983 }
11984
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011985 // There is no value in the cache. Invoke the function and cache result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011986 HandleScope scope(isolate);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011987
11988 Handle<JSFunctionResultCache> cache_handle(cache);
11989 Handle<Object> key_handle(key);
11990 Handle<Object> value;
11991 {
11992 Handle<JSFunction> factory(JSFunction::cast(
11993 cache_handle->get(JSFunctionResultCache::kFactoryIndex)));
11994 // TODO(antonm): consider passing a receiver when constructing a cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011995 Handle<Object> receiver(isolate->global_context()->global());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011996 // This handle is nor shared, nor used later, so it's safe.
11997 Object** argv[] = { key_handle.location() };
11998 bool pending_exception = false;
11999 value = Execution::Call(factory,
12000 receiver,
12001 1,
12002 argv,
12003 &pending_exception);
12004 if (pending_exception) return Failure::Exception();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012005 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012006
12007#ifdef DEBUG
12008 cache_handle->JSFunctionResultCacheVerify();
12009#endif
12010
12011 // Function invocation may have cleared the cache. Reread all the data.
12012 finger_index = cache_handle->finger_index();
12013 size = cache_handle->size();
12014
12015 // If we have spare room, put new data into it, otherwise evict post finger
12016 // entry which is likely to be the least recently used.
12017 int index = -1;
12018 if (size < cache_handle->length()) {
12019 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize);
12020 index = size;
12021 } else {
12022 index = finger_index + JSFunctionResultCache::kEntrySize;
12023 if (index == cache_handle->length()) {
12024 index = JSFunctionResultCache::kEntriesIndex;
12025 }
12026 }
12027
12028 ASSERT(index % 2 == 0);
12029 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
12030 ASSERT(index < cache_handle->length());
12031
12032 cache_handle->set(index, *key_handle);
12033 cache_handle->set(index + 1, *value);
12034 cache_handle->set_finger_index(index);
12035
12036#ifdef DEBUG
12037 cache_handle->JSFunctionResultCacheVerify();
12038#endif
12039
12040 return *value;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012041}
12042
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012043
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012044RUNTIME_FUNCTION(MaybeObject*, Runtime_NewMessageObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012045 HandleScope scope(isolate);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012046 CONVERT_ARG_CHECKED(String, type, 0);
12047 CONVERT_ARG_CHECKED(JSArray, arguments, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012048 return *isolate->factory()->NewJSMessageObject(
12049 type,
12050 arguments,
12051 0,
12052 0,
12053 isolate->factory()->undefined_value(),
12054 isolate->factory()->undefined_value(),
12055 isolate->factory()->undefined_value());
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012056}
12057
12058
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012059RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetType) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012060 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12061 return message->type();
12062}
12063
12064
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012065RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetArguments) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012066 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12067 return message->arguments();
12068}
12069
12070
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012071RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetStartPosition) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012072 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12073 return Smi::FromInt(message->start_position());
12074}
12075
12076
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012077RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetScript) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012078 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12079 return message->script();
12080}
12081
12082
kasper.lund44510672008-07-25 07:37:58 +000012083#ifdef DEBUG
12084// ListNatives is ONLY used by the fuzz-natives.js in debug mode
12085// Exclude the code in release mode.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012086RUNTIME_FUNCTION(MaybeObject*, Runtime_ListNatives) {
mads.s.ager31e71382008-08-13 09:32:07 +000012087 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012088 HandleScope scope;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012089#define COUNT_ENTRY(Name, argc, ressize) + 1
12090 int entry_count = 0
12091 RUNTIME_FUNCTION_LIST(COUNT_ENTRY)
12092 INLINE_FUNCTION_LIST(COUNT_ENTRY)
12093 INLINE_RUNTIME_FUNCTION_LIST(COUNT_ENTRY);
12094#undef COUNT_ENTRY
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012095 Factory* factory = isolate->factory();
12096 Handle<FixedArray> elements = factory->NewFixedArray(entry_count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012097 int index = 0;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012098 bool inline_runtime_functions = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +000012099#define ADD_ENTRY(Name, argc, ressize) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012100 { \
12101 HandleScope inner; \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012102 Handle<String> name; \
12103 /* Inline runtime functions have an underscore in front of the name. */ \
12104 if (inline_runtime_functions) { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012105 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012106 Vector<const char>("_" #Name, StrLength("_" #Name))); \
12107 } else { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012108 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012109 Vector<const char>(#Name, StrLength(#Name))); \
12110 } \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012111 Handle<FixedArray> pair_elements = factory->NewFixedArray(2); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012112 pair_elements->set(0, *name); \
12113 pair_elements->set(1, Smi::FromInt(argc)); \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012114 Handle<JSArray> pair = factory->NewJSArrayWithElements(pair_elements); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012115 elements->set(index++, *pair); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012116 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012117 inline_runtime_functions = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012118 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012119 inline_runtime_functions = true;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012120 INLINE_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012121 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012122#undef ADD_ENTRY
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012123 ASSERT_EQ(index, entry_count);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012124 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012125 return *result;
12126}
kasper.lund44510672008-07-25 07:37:58 +000012127#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012128
12129
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012130RUNTIME_FUNCTION(MaybeObject*, Runtime_Log) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000012131 ASSERT(args.length() == 2);
ager@chromium.org381abbb2009-02-25 13:23:22 +000012132 CONVERT_CHECKED(String, format, args[0]);
12133 CONVERT_CHECKED(JSArray, elms, args[1]);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000012134 Vector<const char> chars = format->ToAsciiVector();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012135 LOGGER->LogRuntime(chars, elms);
12136 return isolate->heap()->undefined_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000012137}
12138
12139
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012140RUNTIME_FUNCTION(MaybeObject*, Runtime_IS_VAR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012141 UNREACHABLE(); // implemented as macro in the parser
12142 return NULL;
12143}
12144
12145
12146// ----------------------------------------------------------------------------
12147// Implementation of Runtime
12148
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012149#define F(name, number_of_args, result_size) \
12150 { Runtime::k##name, Runtime::RUNTIME, #name, \
12151 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012152
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012153
12154#define I(name, number_of_args, result_size) \
12155 { Runtime::kInline##name, Runtime::INLINE, \
12156 "_" #name, NULL, number_of_args, result_size },
12157
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012158static const Runtime::Function kIntrinsicFunctions[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012159 RUNTIME_FUNCTION_LIST(F)
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012160 INLINE_FUNCTION_LIST(I)
12161 INLINE_RUNTIME_FUNCTION_LIST(I)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012162};
12163
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012164
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012165MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Heap* heap,
12166 Object* dictionary) {
12167 ASSERT(Isolate::Current()->heap() == heap);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012168 ASSERT(dictionary != NULL);
12169 ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
12170 for (int i = 0; i < kNumFunctions; ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000012171 Object* name_symbol;
12172 { MaybeObject* maybe_name_symbol =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012173 heap->LookupAsciiSymbol(kIntrinsicFunctions[i].name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012174 if (!maybe_name_symbol->ToObject(&name_symbol)) return maybe_name_symbol;
12175 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012176 StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012177 { MaybeObject* maybe_dictionary = string_dictionary->Add(
12178 String::cast(name_symbol),
12179 Smi::FromInt(i),
12180 PropertyDetails(NONE, NORMAL));
12181 if (!maybe_dictionary->ToObject(&dictionary)) {
12182 // Non-recoverable failure. Calling code must restart heap
12183 // initialization.
12184 return maybe_dictionary;
12185 }
12186 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012187 }
12188 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012189}
12190
12191
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012192const Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
12193 Heap* heap = name->GetHeap();
12194 int entry = heap->intrinsic_function_names()->FindEntry(*name);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012195 if (entry != kNotFound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012196 Object* smi_index = heap->intrinsic_function_names()->ValueAt(entry);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012197 int function_index = Smi::cast(smi_index)->value();
12198 return &(kIntrinsicFunctions[function_index]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012199 }
12200 return NULL;
12201}
12202
12203
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012204const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012205 return &(kIntrinsicFunctions[static_cast<int>(id)]);
12206}
12207
12208
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012209void Runtime::PerformGC(Object* result) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000012210 Isolate* isolate = Isolate::Current();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012211 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000012212 if (failure->IsRetryAfterGC()) {
12213 // Try to do a garbage collection; ignore it if it fails. The C
12214 // entry stub will throw an out-of-memory exception in that case.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000012215 isolate->heap()->CollectGarbage(failure->allocation_space());
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000012216 } else {
12217 // Handle last resort GC and make sure to allow future allocations
12218 // to grow the heap without causing GCs (if possible).
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000012219 isolate->counters()->gc_last_resort_from_js()->Increment();
12220 isolate->heap()->CollectAllGarbage(false);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000012221 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012222}
12223
12224
12225} } // namespace v8::internal