blob: 4997d56df54b8dceb95b98938b0bff0dca4283d7 [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"
danno@chromium.org40cb8782011-05-25 07:58:50 +000045#include "json-parser.h"
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000046#include "liveedit.h"
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000047#include "liveobjectlist-inl.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000048#include "parser.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000049#include "platform.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000050#include "runtime-profiler.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000051#include "runtime.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000052#include "scopeinfo.h"
ager@chromium.org7c537e22008-10-16 08:43:32 +000053#include "smart-pointer.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000054#include "string-search.h"
ager@chromium.org18ad94b2009-09-02 08:22:29 +000055#include "stub-cache.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000056#include "v8threads.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000057#include "vm-state-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000058
kasperl@chromium.org71affb52009-05-26 05:44:31 +000059namespace v8 {
60namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000061
62
ager@chromium.org3e875802009-06-29 08:26:34 +000063#define RUNTIME_ASSERT(value) \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000064 if (!(value)) return isolate->ThrowIllegalOperation();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000065
66// Cast the given object to a value of the specified type and store
67// it in a variable with the given name. If the object is not of the
68// expected type call IllegalOperation and return.
69#define CONVERT_CHECKED(Type, name, obj) \
70 RUNTIME_ASSERT(obj->Is##Type()); \
71 Type* name = Type::cast(obj);
72
73#define CONVERT_ARG_CHECKED(Type, name, index) \
74 RUNTIME_ASSERT(args[index]->Is##Type()); \
75 Handle<Type> name = args.at<Type>(index);
76
kasper.lundbd3ec4e2008-07-09 11:06:54 +000077// Cast the given object to a boolean and store it in a variable with
78// the given name. If the object is not a boolean call IllegalOperation
79// and return.
80#define CONVERT_BOOLEAN_CHECKED(name, obj) \
81 RUNTIME_ASSERT(obj->IsBoolean()); \
82 bool name = (obj)->IsTrue();
83
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000084// Cast the given object to a Smi and store its value in an int variable
85// with the given name. If the object is not a Smi call IllegalOperation
86// and return.
87#define CONVERT_SMI_CHECKED(name, obj) \
88 RUNTIME_ASSERT(obj->IsSmi()); \
89 int name = Smi::cast(obj)->value();
90
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000091// Cast the given object to a double and store it in a variable with
92// the given name. If the object is not a number (as opposed to
93// the number not-a-number) call IllegalOperation and return.
94#define CONVERT_DOUBLE_CHECKED(name, obj) \
95 RUNTIME_ASSERT(obj->IsNumber()); \
96 double name = (obj)->Number();
97
98// Call the specified converter on the object *comand store the result in
99// a variable of the specified type with the given name. If the
100// object is not a Number call IllegalOperation and return.
101#define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \
102 RUNTIME_ASSERT(obj->IsNumber()); \
103 type name = NumberTo##Type(obj);
104
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000105
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000106MUST_USE_RESULT static MaybeObject* DeepCopyBoilerplate(Isolate* isolate,
107 JSObject* boilerplate) {
108 StackLimitCheck check(isolate);
109 if (check.HasOverflowed()) return isolate->StackOverflow();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000110
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000111 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000112 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000113 { MaybeObject* maybe_result = heap->CopyJSObject(boilerplate);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000114 if (!maybe_result->ToObject(&result)) return maybe_result;
115 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000116 JSObject* copy = JSObject::cast(result);
117
118 // Deep copy local properties.
119 if (copy->HasFastProperties()) {
120 FixedArray* properties = copy->properties();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000121 for (int i = 0; i < properties->length(); i++) {
122 Object* value = properties->get(i);
123 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000124 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000125 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000126 if (!maybe_result->ToObject(&result)) return maybe_result;
127 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000128 properties->set(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000129 }
130 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000131 int nof = copy->map()->inobject_properties();
132 for (int i = 0; i < nof; i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000133 Object* value = copy->InObjectPropertyAt(i);
134 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000135 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000136 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000137 if (!maybe_result->ToObject(&result)) return maybe_result;
138 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000139 copy->InObjectPropertyAtPut(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000140 }
141 }
142 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000143 { MaybeObject* maybe_result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000144 heap->AllocateFixedArray(copy->NumberOfLocalProperties(NONE));
lrn@chromium.org303ada72010-10-27 09:33:13 +0000145 if (!maybe_result->ToObject(&result)) return maybe_result;
146 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000147 FixedArray* names = FixedArray::cast(result);
148 copy->GetLocalPropertyNames(names, 0);
149 for (int i = 0; i < names->length(); i++) {
150 ASSERT(names->get(i)->IsString());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000151 String* key_string = String::cast(names->get(i));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000152 PropertyAttributes attributes =
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000153 copy->GetLocalPropertyAttribute(key_string);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000154 // Only deep copy fields from the object literal expression.
155 // In particular, don't try to copy the length attribute of
156 // an array.
157 if (attributes != NONE) continue;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000158 Object* value =
159 copy->GetProperty(key_string, &attributes)->ToObjectUnchecked();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000160 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000161 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000162 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000163 if (!maybe_result->ToObject(&result)) return maybe_result;
164 }
165 { MaybeObject* maybe_result =
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000166 // Creating object copy for literals. No strict mode needed.
167 copy->SetProperty(key_string, result, NONE, kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000168 if (!maybe_result->ToObject(&result)) return maybe_result;
169 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000170 }
171 }
172 }
173
174 // Deep copy local elements.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000175 // Pixel elements cannot be created using an object literal.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000176 ASSERT(!copy->HasExternalArrayElements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000177 switch (copy->GetElementsKind()) {
178 case JSObject::FAST_ELEMENTS: {
179 FixedArray* elements = FixedArray::cast(copy->elements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000180 if (elements->map() == heap->fixed_cow_array_map()) {
181 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000182#ifdef DEBUG
183 for (int i = 0; i < elements->length(); i++) {
184 ASSERT(!elements->get(i)->IsJSObject());
185 }
186#endif
187 } else {
188 for (int i = 0; i < elements->length(); i++) {
189 Object* value = elements->get(i);
190 if (value->IsJSObject()) {
191 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000192 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
193 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000194 if (!maybe_result->ToObject(&result)) return maybe_result;
195 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000196 elements->set(i, result);
197 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000198 }
199 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000200 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000201 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000202 case JSObject::DICTIONARY_ELEMENTS: {
203 NumberDictionary* element_dictionary = copy->element_dictionary();
204 int capacity = element_dictionary->Capacity();
205 for (int i = 0; i < capacity; i++) {
206 Object* k = element_dictionary->KeyAt(i);
207 if (element_dictionary->IsKey(k)) {
208 Object* value = element_dictionary->ValueAt(i);
209 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000210 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000211 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
212 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000213 if (!maybe_result->ToObject(&result)) return maybe_result;
214 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000215 element_dictionary->ValueAtPut(i, result);
216 }
217 }
218 }
219 break;
220 }
221 default:
222 UNREACHABLE();
223 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000224 }
225 return copy;
226}
227
228
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000229RUNTIME_FUNCTION(MaybeObject*, Runtime_CloneLiteralBoilerplate) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000230 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000231 return DeepCopyBoilerplate(isolate, boilerplate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000232}
233
234
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000235RUNTIME_FUNCTION(MaybeObject*, Runtime_CloneShallowLiteralBoilerplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000236 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000237 return isolate->heap()->CopyJSObject(boilerplate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000238}
239
240
ager@chromium.org236ad962008-09-25 09:45:57 +0000241static Handle<Map> ComputeObjectLiteralMap(
242 Handle<Context> context,
243 Handle<FixedArray> constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000244 bool* is_result_from_cache) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000245 Isolate* isolate = context->GetIsolate();
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000246 int properties_length = constant_properties->length();
247 int number_of_properties = properties_length / 2;
ager@chromium.org236ad962008-09-25 09:45:57 +0000248 if (FLAG_canonicalize_object_literal_maps) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000249 // Check that there are only symbols and array indices among keys.
ager@chromium.org236ad962008-09-25 09:45:57 +0000250 int number_of_symbol_keys = 0;
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000251 for (int p = 0; p != properties_length; p += 2) {
252 Object* key = constant_properties->get(p);
253 uint32_t element_index = 0;
254 if (key->IsSymbol()) {
255 number_of_symbol_keys++;
256 } else if (key->ToArrayIndex(&element_index)) {
257 // An index key does not require space in the property backing store.
258 number_of_properties--;
259 } else {
260 // Bail out as a non-symbol non-index key makes caching impossible.
261 // ASSERT to make sure that the if condition after the loop is false.
262 ASSERT(number_of_symbol_keys != number_of_properties);
263 break;
264 }
ager@chromium.org236ad962008-09-25 09:45:57 +0000265 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000266 // If we only have symbols and array indices among keys then we can
267 // use the map cache in the global context.
ager@chromium.org236ad962008-09-25 09:45:57 +0000268 const int kMaxKeys = 10;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000269 if ((number_of_symbol_keys == number_of_properties) &&
270 (number_of_symbol_keys < kMaxKeys)) {
ager@chromium.org236ad962008-09-25 09:45:57 +0000271 // Create the fixed array with the key.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000272 Handle<FixedArray> keys =
273 isolate->factory()->NewFixedArray(number_of_symbol_keys);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000274 if (number_of_symbol_keys > 0) {
275 int index = 0;
276 for (int p = 0; p < properties_length; p += 2) {
277 Object* key = constant_properties->get(p);
278 if (key->IsSymbol()) {
279 keys->set(index++, key);
280 }
281 }
282 ASSERT(index == number_of_symbol_keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000283 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000284 *is_result_from_cache = true;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000285 return isolate->factory()->ObjectLiteralMapFromCache(context, keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000286 }
287 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000288 *is_result_from_cache = false;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000289 return isolate->factory()->CopyMap(
ager@chromium.org32912102009-01-16 10:38:43 +0000290 Handle<Map>(context->object_function()->initial_map()),
291 number_of_properties);
ager@chromium.org236ad962008-09-25 09:45:57 +0000292}
293
294
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000295static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000296 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000297 Handle<FixedArray> literals,
298 Handle<FixedArray> constant_properties);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000299
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000300
301static Handle<Object> CreateObjectLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000302 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000303 Handle<FixedArray> literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000304 Handle<FixedArray> constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000305 bool should_have_fast_elements,
306 bool has_function_literal) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000307 // Get the global context from the literals array. This is the
308 // context in which the function was created and we use the object
309 // function from this context to create the object literal. We do
310 // not use the object function from the current global context
311 // because this might be the object function from another context
312 // which we should not have access to.
ager@chromium.org236ad962008-09-25 09:45:57 +0000313 Handle<Context> context =
314 Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals));
315
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000316 // In case we have function literals, we want the object to be in
317 // slow properties mode for now. We don't go in the map cache because
318 // maps with constant functions can't be shared if the functions are
319 // not the same (which is the common case).
320 bool is_result_from_cache = false;
321 Handle<Map> map = has_function_literal
322 ? Handle<Map>(context->object_function()->initial_map())
323 : ComputeObjectLiteralMap(context,
324 constant_properties,
325 &is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000326
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000327 Handle<JSObject> boilerplate = isolate->factory()->NewJSObjectFromMap(map);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000328
329 // Normalize the elements of the boilerplate to save space if needed.
330 if (!should_have_fast_elements) NormalizeElements(boilerplate);
331
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000332 // Add the constant properties to the boilerplate.
333 int length = constant_properties->length();
334 bool should_transform =
335 !is_result_from_cache && boilerplate->HasFastProperties();
336 if (should_transform || has_function_literal) {
337 // Normalize the properties of object to avoid n^2 behavior
338 // when extending the object multiple properties. Indicate the number of
339 // properties to be added.
340 NormalizeProperties(boilerplate, KEEP_INOBJECT_PROPERTIES, length / 2);
341 }
342
343 for (int index = 0; index < length; index +=2) {
344 Handle<Object> key(constant_properties->get(index+0), isolate);
345 Handle<Object> value(constant_properties->get(index+1), isolate);
346 if (value->IsFixedArray()) {
347 // The value contains the constant_properties of a
348 // simple object or array literal.
349 Handle<FixedArray> array = Handle<FixedArray>::cast(value);
350 value = CreateLiteralBoilerplate(isolate, literals, array);
351 if (value.is_null()) return value;
352 }
353 Handle<Object> result;
354 uint32_t element_index = 0;
355 if (key->IsSymbol()) {
356 if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) {
357 // Array index as string (uint32).
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000358 result = SetOwnElement(boilerplate,
359 element_index,
360 value,
361 kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000362 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000363 Handle<String> name(String::cast(*key));
364 ASSERT(!name->AsArrayIndex(&element_index));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000365 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
366 value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000367 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000368 } else if (key->ToArrayIndex(&element_index)) {
369 // Array index (uint32).
370 result = SetOwnElement(boilerplate,
371 element_index,
372 value,
373 kNonStrictMode);
374 } else {
375 // Non-uint32 number.
376 ASSERT(key->IsNumber());
377 double num = key->Number();
378 char arr[100];
379 Vector<char> buffer(arr, ARRAY_SIZE(arr));
380 const char* str = DoubleToCString(num, buffer);
381 Handle<String> name =
382 isolate->factory()->NewStringFromAscii(CStrVector(str));
383 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
384 value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000385 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000386 // If setting the property on the boilerplate throws an
387 // exception, the exception is converted to an empty handle in
388 // the handle based operations. In that case, we need to
389 // convert back to an exception.
390 if (result.is_null()) return result;
391 }
392
393 // Transform to fast properties if necessary. For object literals with
394 // containing function literals we defer this operation until after all
395 // computed properties have been assigned so that we can generate
396 // constant function properties.
397 if (should_transform && !has_function_literal) {
398 TransformToFastProperties(boilerplate,
399 boilerplate->map()->unused_property_fields());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000400 }
401
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000402 return boilerplate;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000403}
404
405
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000406static Handle<Object> CreateArrayLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000407 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000408 Handle<FixedArray> literals,
409 Handle<FixedArray> elements) {
410 // Create the JSArray.
411 Handle<JSFunction> constructor(
412 JSFunction::GlobalContextFromLiterals(*literals)->array_function());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000413 Handle<Object> object = isolate->factory()->NewJSObject(constructor);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000414
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000415 const bool is_cow =
416 (elements->map() == isolate->heap()->fixed_cow_array_map());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000417 Handle<FixedArray> copied_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000418 is_cow ? elements : isolate->factory()->CopyFixedArray(elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000419
420 Handle<FixedArray> content = Handle<FixedArray>::cast(copied_elements);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000421 if (is_cow) {
422#ifdef DEBUG
423 // Copy-on-write arrays must be shallow (and simple).
424 for (int i = 0; i < content->length(); i++) {
425 ASSERT(!content->get(i)->IsFixedArray());
426 }
427#endif
428 } else {
429 for (int i = 0; i < content->length(); i++) {
430 if (content->get(i)->IsFixedArray()) {
431 // The value contains the constant_properties of a
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000432 // simple object or array literal.
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000433 Handle<FixedArray> fa(FixedArray::cast(content->get(i)));
434 Handle<Object> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000435 CreateLiteralBoilerplate(isolate, literals, fa);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000436 if (result.is_null()) return result;
437 content->set(i, *result);
438 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000439 }
440 }
441
442 // Set the elements.
443 Handle<JSArray>::cast(object)->SetContent(*content);
444 return object;
445}
446
447
448static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000449 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000450 Handle<FixedArray> literals,
451 Handle<FixedArray> array) {
452 Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000453 const bool kHasNoFunctionLiteral = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000454 switch (CompileTimeValue::GetType(array)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000455 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000456 return CreateObjectLiteralBoilerplate(isolate,
457 literals,
458 elements,
459 true,
460 kHasNoFunctionLiteral);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000461 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000462 return CreateObjectLiteralBoilerplate(isolate,
463 literals,
464 elements,
465 false,
466 kHasNoFunctionLiteral);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000467 case CompileTimeValue::ARRAY_LITERAL:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000468 return CreateArrayLiteralBoilerplate(isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000469 default:
470 UNREACHABLE();
471 return Handle<Object>::null();
472 }
473}
474
475
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000476RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralBoilerplate) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000477 // Takes a FixedArray of elements containing the literal elements of
478 // the array literal and produces JSArray with those elements.
479 // Additionally takes the literals array of the surrounding function
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000480 // which contains the context from which to get the Array function
481 // to use for creating the array literal.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000482 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000483 ASSERT(args.length() == 3);
484 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
485 CONVERT_SMI_CHECKED(literals_index, args[1]);
486 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000487
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000488 Handle<Object> object =
489 CreateArrayLiteralBoilerplate(isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000490 if (object.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000491
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000492 // Update the functions literal and return the boilerplate.
493 literals->set(literals_index, *object);
494 return *object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000495}
496
497
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000498RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000499 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000500 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000501 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
502 CONVERT_SMI_CHECKED(literals_index, args[1]);
503 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000504 CONVERT_SMI_CHECKED(flags, args[3]);
505 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
506 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000507
508 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000509 Handle<Object> boilerplate(literals->get(literals_index), isolate);
510 if (*boilerplate == isolate->heap()->undefined_value()) {
511 boilerplate = CreateObjectLiteralBoilerplate(isolate,
512 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000513 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000514 should_have_fast_elements,
515 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000516 if (boilerplate.is_null()) return Failure::Exception();
517 // Update the functions literal and return the boilerplate.
518 literals->set(literals_index, *boilerplate);
519 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000520 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000521}
522
523
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000524RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000525 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000526 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000527 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
528 CONVERT_SMI_CHECKED(literals_index, args[1]);
529 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000530 CONVERT_SMI_CHECKED(flags, args[3]);
531 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
532 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000533
534 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000535 Handle<Object> boilerplate(literals->get(literals_index), isolate);
536 if (*boilerplate == isolate->heap()->undefined_value()) {
537 boilerplate = CreateObjectLiteralBoilerplate(isolate,
538 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000539 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000540 should_have_fast_elements,
541 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000542 if (boilerplate.is_null()) return Failure::Exception();
543 // Update the functions literal and return the boilerplate.
544 literals->set(literals_index, *boilerplate);
545 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000546 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000547}
548
549
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000550RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000551 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000552 ASSERT(args.length() == 3);
553 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
554 CONVERT_SMI_CHECKED(literals_index, args[1]);
555 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
556
557 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000558 Handle<Object> boilerplate(literals->get(literals_index), isolate);
559 if (*boilerplate == isolate->heap()->undefined_value()) {
560 boilerplate = CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000561 if (boilerplate.is_null()) return Failure::Exception();
562 // Update the functions literal and return the boilerplate.
563 literals->set(literals_index, *boilerplate);
564 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000565 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000566}
567
568
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000569RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000570 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000571 ASSERT(args.length() == 3);
572 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
573 CONVERT_SMI_CHECKED(literals_index, args[1]);
574 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
575
576 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000577 Handle<Object> boilerplate(literals->get(literals_index), isolate);
578 if (*boilerplate == isolate->heap()->undefined_value()) {
579 boilerplate = CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000580 if (boilerplate.is_null()) return Failure::Exception();
581 // Update the functions literal and return the boilerplate.
582 literals->set(literals_index, *boilerplate);
583 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000584 if (JSObject::cast(*boilerplate)->elements()->map() ==
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000585 isolate->heap()->fixed_cow_array_map()) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000586 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000587 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000588 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000589}
590
591
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000592RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSProxy) {
593 ASSERT(args.length() == 2);
594 Object* handler = args[0];
595 Object* prototype = args[1];
596 Object* used_prototype =
597 (prototype->IsJSObject() || prototype->IsJSProxy()) ? prototype
598 : isolate->heap()->null_value();
599 return isolate->heap()->AllocateJSProxy(handler, used_prototype);
600}
601
602
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000603RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateCatchExtensionObject) {
ager@chromium.org32912102009-01-16 10:38:43 +0000604 ASSERT(args.length() == 2);
605 CONVERT_CHECKED(String, key, args[0]);
606 Object* value = args[1];
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000607 ASSERT(!value->IsFailure());
ager@chromium.org32912102009-01-16 10:38:43 +0000608 // Create a catch context extension object.
609 JSFunction* constructor =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000610 isolate->context()->global_context()->
611 context_extension_function();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000612 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000613 { MaybeObject* maybe_object = isolate->heap()->AllocateJSObject(constructor);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000614 if (!maybe_object->ToObject(&object)) return maybe_object;
615 }
ager@chromium.org32912102009-01-16 10:38:43 +0000616 // Assign the exception value to the catch variable and make sure
617 // that the catch variable is DontDelete.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000618 { MaybeObject* maybe_value =
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000619 // Passing non-strict per ECMA-262 5th Ed. 12.14. Catch, bullet #4.
620 JSObject::cast(object)->SetProperty(
621 key, value, DONT_DELETE, kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000622 if (!maybe_value->ToObject(&value)) return maybe_value;
623 }
ager@chromium.org32912102009-01-16 10:38:43 +0000624 return object;
625}
626
627
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000628RUNTIME_FUNCTION(MaybeObject*, Runtime_ClassOf) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000629 NoHandleAllocation ha;
630 ASSERT(args.length() == 1);
631 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000632 if (!obj->IsJSObject()) return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000633 return JSObject::cast(obj)->class_name();
634}
635
ager@chromium.org7c537e22008-10-16 08:43:32 +0000636
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000637RUNTIME_FUNCTION(MaybeObject*, Runtime_IsInPrototypeChain) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000638 NoHandleAllocation ha;
639 ASSERT(args.length() == 2);
640 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
641 Object* O = args[0];
642 Object* V = args[1];
643 while (true) {
644 Object* prototype = V->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000645 if (prototype->IsNull()) return isolate->heap()->false_value();
646 if (O == prototype) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000647 V = prototype;
648 }
649}
650
651
ager@chromium.org9085a012009-05-11 19:22:57 +0000652// Inserts an object as the hidden prototype of another object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000653RUNTIME_FUNCTION(MaybeObject*, Runtime_SetHiddenPrototype) {
ager@chromium.org9085a012009-05-11 19:22:57 +0000654 NoHandleAllocation ha;
655 ASSERT(args.length() == 2);
656 CONVERT_CHECKED(JSObject, jsobject, args[0]);
657 CONVERT_CHECKED(JSObject, proto, args[1]);
658
659 // Sanity checks. The old prototype (that we are replacing) could
660 // theoretically be null, but if it is not null then check that we
661 // didn't already install a hidden prototype here.
662 RUNTIME_ASSERT(!jsobject->GetPrototype()->IsHeapObject() ||
663 !HeapObject::cast(jsobject->GetPrototype())->map()->is_hidden_prototype());
664 RUNTIME_ASSERT(!proto->map()->is_hidden_prototype());
665
666 // Allocate up front before we start altering state in case we get a GC.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000667 Object* map_or_failure;
668 { MaybeObject* maybe_map_or_failure = proto->map()->CopyDropTransitions();
669 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
670 return maybe_map_or_failure;
671 }
672 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000673 Map* new_proto_map = Map::cast(map_or_failure);
674
lrn@chromium.org303ada72010-10-27 09:33:13 +0000675 { MaybeObject* maybe_map_or_failure = jsobject->map()->CopyDropTransitions();
676 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
677 return maybe_map_or_failure;
678 }
679 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000680 Map* new_map = Map::cast(map_or_failure);
681
682 // Set proto's prototype to be the old prototype of the object.
683 new_proto_map->set_prototype(jsobject->GetPrototype());
684 proto->set_map(new_proto_map);
685 new_proto_map->set_is_hidden_prototype();
686
687 // Set the object's prototype to proto.
688 new_map->set_prototype(proto);
689 jsobject->set_map(new_map);
690
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000691 return isolate->heap()->undefined_value();
ager@chromium.org9085a012009-05-11 19:22:57 +0000692}
693
694
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000695RUNTIME_FUNCTION(MaybeObject*, Runtime_IsConstructCall) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000696 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +0000697 ASSERT(args.length() == 0);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000698 JavaScriptFrameIterator it(isolate);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000699 return isolate->heap()->ToBoolean(it.frame()->IsConstructor());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000700}
701
702
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000703// Recursively traverses hidden prototypes if property is not found
704static void GetOwnPropertyImplementation(JSObject* obj,
705 String* name,
706 LookupResult* result) {
707 obj->LocalLookupRealNamedProperty(name, result);
708
709 if (!result->IsProperty()) {
710 Object* proto = obj->GetPrototype();
711 if (proto->IsJSObject() &&
712 JSObject::cast(proto)->map()->is_hidden_prototype())
713 GetOwnPropertyImplementation(JSObject::cast(proto),
714 name, result);
715 }
716}
717
718
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000719static bool CheckAccessException(LookupResult* result,
720 v8::AccessType access_type) {
721 if (result->type() == CALLBACKS) {
722 Object* callback = result->GetCallbackObject();
723 if (callback->IsAccessorInfo()) {
724 AccessorInfo* info = AccessorInfo::cast(callback);
725 bool can_access =
726 (access_type == v8::ACCESS_HAS &&
727 (info->all_can_read() || info->all_can_write())) ||
728 (access_type == v8::ACCESS_GET && info->all_can_read()) ||
729 (access_type == v8::ACCESS_SET && info->all_can_write());
730 return can_access;
731 }
732 }
733
734 return false;
735}
736
737
738static bool CheckAccess(JSObject* obj,
739 String* name,
740 LookupResult* result,
741 v8::AccessType access_type) {
742 ASSERT(result->IsProperty());
743
744 JSObject* holder = result->holder();
745 JSObject* current = obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000746 Isolate* isolate = obj->GetIsolate();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000747 while (true) {
748 if (current->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000749 !isolate->MayNamedAccess(current, name, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000750 // Access check callback denied the access, but some properties
751 // can have a special permissions which override callbacks descision
752 // (currently see v8::AccessControl).
753 break;
754 }
755
756 if (current == holder) {
757 return true;
758 }
759
760 current = JSObject::cast(current->GetPrototype());
761 }
762
763 // API callbacks can have per callback access exceptions.
764 switch (result->type()) {
765 case CALLBACKS: {
766 if (CheckAccessException(result, access_type)) {
767 return true;
768 }
769 break;
770 }
771 case INTERCEPTOR: {
772 // If the object has an interceptor, try real named properties.
773 // Overwrite the result to fetch the correct property later.
774 holder->LookupRealNamedProperty(name, result);
775 if (result->IsProperty()) {
776 if (CheckAccessException(result, access_type)) {
777 return true;
778 }
779 }
780 break;
781 }
782 default:
783 break;
784 }
785
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000786 isolate->ReportFailedAccessCheck(current, access_type);
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000787 return false;
788}
789
790
791// TODO(1095): we should traverse hidden prototype hierachy as well.
792static bool CheckElementAccess(JSObject* obj,
793 uint32_t index,
794 v8::AccessType access_type) {
795 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000796 !obj->GetIsolate()->MayIndexedAccess(obj, index, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000797 return false;
798 }
799
800 return true;
801}
802
803
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000804// Enumerator used as indices into the array returned from GetOwnProperty
805enum PropertyDescriptorIndices {
806 IS_ACCESSOR_INDEX,
807 VALUE_INDEX,
808 GETTER_INDEX,
809 SETTER_INDEX,
810 WRITABLE_INDEX,
811 ENUMERABLE_INDEX,
812 CONFIGURABLE_INDEX,
813 DESCRIPTOR_SIZE
814};
815
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000816// Returns an array with the property description:
817// if args[1] is not a property on args[0]
818// returns undefined
819// if args[1] is a data property on args[0]
820// [false, value, Writeable, Enumerable, Configurable]
821// if args[1] is an accessor on args[0]
822// [true, GetFunction, SetFunction, Enumerable, Configurable]
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000823RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOwnProperty) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000824 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000825 Heap* heap = isolate->heap();
826 HandleScope scope(isolate);
827 Handle<FixedArray> elms = isolate->factory()->NewFixedArray(DESCRIPTOR_SIZE);
828 Handle<JSArray> desc = isolate->factory()->NewJSArrayWithElements(elms);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000829 LookupResult result;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000830 CONVERT_ARG_CHECKED(JSObject, obj, 0);
831 CONVERT_ARG_CHECKED(String, name, 1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000832
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000833 // This could be an element.
834 uint32_t index;
835 if (name->AsArrayIndex(&index)) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000836 switch (obj->HasLocalElement(index)) {
837 case JSObject::UNDEFINED_ELEMENT:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000838 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000839
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000840 case JSObject::STRING_CHARACTER_ELEMENT: {
841 // Special handling of string objects according to ECMAScript 5
842 // 15.5.5.2. Note that this might be a string object with elements
843 // other than the actual string value. This is covered by the
844 // subsequent cases.
845 Handle<JSValue> js_value = Handle<JSValue>::cast(obj);
846 Handle<String> str(String::cast(js_value->value()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000847 Handle<String> substr = SubString(str, index, index + 1, NOT_TENURED);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000848
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000849 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000850 elms->set(VALUE_INDEX, *substr);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000851 elms->set(WRITABLE_INDEX, heap->false_value());
852 elms->set(ENUMERABLE_INDEX, heap->false_value());
853 elms->set(CONFIGURABLE_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000854 return *desc;
855 }
856
857 case JSObject::INTERCEPTED_ELEMENT:
858 case JSObject::FAST_ELEMENT: {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000859 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000860 Handle<Object> value = GetElement(obj, index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000861 RETURN_IF_EMPTY_HANDLE(isolate, value);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000862 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000863 elms->set(WRITABLE_INDEX, heap->true_value());
864 elms->set(ENUMERABLE_INDEX, heap->true_value());
865 elms->set(CONFIGURABLE_INDEX, heap->true_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000866 return *desc;
867 }
868
869 case JSObject::DICTIONARY_ELEMENT: {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000870 Handle<JSObject> holder = obj;
871 if (obj->IsJSGlobalProxy()) {
872 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000873 if (proto->IsNull()) return heap->undefined_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000874 ASSERT(proto->IsJSGlobalObject());
875 holder = Handle<JSObject>(JSObject::cast(proto));
876 }
877 NumberDictionary* dictionary = holder->element_dictionary();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000878 int entry = dictionary->FindEntry(index);
879 ASSERT(entry != NumberDictionary::kNotFound);
880 PropertyDetails details = dictionary->DetailsAt(entry);
881 switch (details.type()) {
882 case CALLBACKS: {
883 // This is an accessor property with getter and/or setter.
884 FixedArray* callbacks =
885 FixedArray::cast(dictionary->ValueAt(entry));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000886 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000887 if (CheckElementAccess(*obj, index, v8::ACCESS_GET)) {
888 elms->set(GETTER_INDEX, callbacks->get(0));
889 }
890 if (CheckElementAccess(*obj, index, v8::ACCESS_SET)) {
891 elms->set(SETTER_INDEX, callbacks->get(1));
892 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000893 break;
894 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000895 case NORMAL: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000896 // This is a data property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000897 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000898 Handle<Object> value = GetElement(obj, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000899 ASSERT(!value.is_null());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000900 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000901 elms->set(WRITABLE_INDEX, heap->ToBoolean(!details.IsReadOnly()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000902 break;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000903 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000904 default:
905 UNREACHABLE();
906 break;
907 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000908 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!details.IsDontEnum()));
909 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!details.IsDontDelete()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000910 return *desc;
911 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000912 }
913 }
914
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000915 // Use recursive implementation to also traverse hidden prototypes
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000916 GetOwnPropertyImplementation(*obj, *name, &result);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000917
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000918 if (!result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000919 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000920 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000921
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000922 if (!CheckAccess(*obj, *name, &result, v8::ACCESS_HAS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000923 return heap->false_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000924 }
925
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000926 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!result.IsDontEnum()));
927 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!result.IsDontDelete()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000928
929 bool is_js_accessor = (result.type() == CALLBACKS) &&
930 (result.GetCallbackObject()->IsFixedArray());
931
932 if (is_js_accessor) {
933 // __defineGetter__/__defineSetter__ callback.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000934 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000935
936 FixedArray* structure = FixedArray::cast(result.GetCallbackObject());
937 if (CheckAccess(*obj, *name, &result, v8::ACCESS_GET)) {
938 elms->set(GETTER_INDEX, structure->get(0));
939 }
940 if (CheckAccess(*obj, *name, &result, v8::ACCESS_SET)) {
941 elms->set(SETTER_INDEX, structure->get(1));
942 }
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000943 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000944 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
945 elms->set(WRITABLE_INDEX, heap->ToBoolean(!result.IsReadOnly()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000946
947 PropertyAttributes attrs;
948 Object* value;
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000949 // GetProperty will check access and report any violations.
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000950 { MaybeObject* maybe_value = obj->GetProperty(*obj, &result, *name, &attrs);
951 if (!maybe_value->ToObject(&value)) return maybe_value;
952 }
953 elms->set(VALUE_INDEX, value);
954 }
955
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000956 return *desc;
957}
958
959
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000960RUNTIME_FUNCTION(MaybeObject*, Runtime_PreventExtensions) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000961 ASSERT(args.length() == 1);
962 CONVERT_CHECKED(JSObject, obj, args[0]);
963 return obj->PreventExtensions();
964}
965
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000966
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000967RUNTIME_FUNCTION(MaybeObject*, Runtime_IsExtensible) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000968 ASSERT(args.length() == 1);
969 CONVERT_CHECKED(JSObject, obj, args[0]);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000970 if (obj->IsJSGlobalProxy()) {
971 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000972 if (proto->IsNull()) return isolate->heap()->false_value();
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000973 ASSERT(proto->IsJSGlobalObject());
974 obj = JSObject::cast(proto);
975 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000976 return obj->map()->is_extensible() ? isolate->heap()->true_value()
977 : isolate->heap()->false_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000978}
979
980
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000981RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000982 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000983 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000984 CONVERT_ARG_CHECKED(JSRegExp, re, 0);
985 CONVERT_ARG_CHECKED(String, pattern, 1);
986 CONVERT_ARG_CHECKED(String, flags, 2);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000987 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags);
988 if (result.is_null()) return Failure::Exception();
989 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000990}
991
992
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000993RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateApiFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000994 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000995 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000996 CONVERT_ARG_CHECKED(FunctionTemplateInfo, data, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000997 return *isolate->factory()->CreateApiFunction(data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000998}
999
1000
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001001RUNTIME_FUNCTION(MaybeObject*, Runtime_IsTemplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001002 ASSERT(args.length() == 1);
1003 Object* arg = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001004 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001005 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001006}
1007
1008
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001009RUNTIME_FUNCTION(MaybeObject*, Runtime_GetTemplateField) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001010 ASSERT(args.length() == 2);
1011 CONVERT_CHECKED(HeapObject, templ, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001012 CONVERT_CHECKED(Smi, field, args[1]);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001013 int index = field->value();
1014 int offset = index * kPointerSize + HeapObject::kHeaderSize;
1015 InstanceType type = templ->map()->instance_type();
1016 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
1017 type == OBJECT_TEMPLATE_INFO_TYPE);
1018 RUNTIME_ASSERT(offset > 0);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001019 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001020 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
1021 } else {
1022 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
1023 }
1024 return *HeapObject::RawField(templ, offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001025}
1026
1027
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001028RUNTIME_FUNCTION(MaybeObject*, Runtime_DisableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001029 ASSERT(args.length() == 1);
1030 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001031 Map* old_map = object->map();
1032 bool needs_access_checks = old_map->is_access_check_needed();
1033 if (needs_access_checks) {
1034 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001035 Object* new_map;
1036 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1037 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1038 }
ager@chromium.org32912102009-01-16 10:38:43 +00001039
1040 Map::cast(new_map)->set_is_access_check_needed(false);
1041 object->set_map(Map::cast(new_map));
1042 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001043 return needs_access_checks ? isolate->heap()->true_value()
1044 : isolate->heap()->false_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001045}
1046
1047
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001048RUNTIME_FUNCTION(MaybeObject*, Runtime_EnableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001049 ASSERT(args.length() == 1);
1050 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001051 Map* old_map = object->map();
1052 if (!old_map->is_access_check_needed()) {
1053 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001054 Object* new_map;
1055 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1056 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1057 }
ager@chromium.org32912102009-01-16 10:38:43 +00001058
1059 Map::cast(new_map)->set_is_access_check_needed(true);
1060 object->set_map(Map::cast(new_map));
1061 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001062 return isolate->heap()->undefined_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001063}
1064
1065
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001066static Failure* ThrowRedeclarationError(Isolate* isolate,
1067 const char* type,
1068 Handle<String> name) {
1069 HandleScope scope(isolate);
1070 Handle<Object> type_handle =
1071 isolate->factory()->NewStringFromAscii(CStrVector(type));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001072 Handle<Object> args[2] = { type_handle, name };
1073 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001074 isolate->factory()->NewTypeError("redeclaration", HandleVector(args, 2));
1075 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001076}
1077
1078
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001079RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001080 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001081 HandleScope scope(isolate);
1082 Handle<GlobalObject> global = Handle<GlobalObject>(
1083 isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001084
ager@chromium.org3811b432009-10-28 14:53:37 +00001085 Handle<Context> context = args.at<Context>(0);
1086 CONVERT_ARG_CHECKED(FixedArray, pairs, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001087 bool is_eval = Smi::cast(args[2])->value() == 1;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001088 StrictModeFlag strict_mode =
1089 static_cast<StrictModeFlag>(Smi::cast(args[3])->value());
1090 ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001091
1092 // Compute the property attributes. According to ECMA-262, section
1093 // 13, page 71, the property must be read-only and
1094 // non-deletable. However, neither SpiderMonkey nor KJS creates the
1095 // property as read-only, so we don't either.
1096 PropertyAttributes base = is_eval ? NONE : DONT_DELETE;
1097
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001098 // Traverse the name/value pairs and set the properties.
1099 int length = pairs->length();
1100 for (int i = 0; i < length; i += 2) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001101 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001102 Handle<String> name(String::cast(pairs->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001103 Handle<Object> value(pairs->get(i + 1), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001104
1105 // We have to declare a global const property. To capture we only
1106 // assign to it when evaluating the assignment for "const x =
1107 // <expr>" the initial value is the hole.
1108 bool is_const_property = value->IsTheHole();
1109
1110 if (value->IsUndefined() || is_const_property) {
1111 // Lookup the property in the global object, and don't set the
1112 // value of the variable if the property is already there.
1113 LookupResult lookup;
1114 global->Lookup(*name, &lookup);
1115 if (lookup.IsProperty()) {
1116 // Determine if the property is local by comparing the holder
1117 // against the global object. The information will be used to
1118 // avoid throwing re-declaration errors when declaring
1119 // variables or constants that exist in the prototype chain.
1120 bool is_local = (*global == lookup.holder());
1121 // Get the property attributes and determine if the property is
1122 // read-only.
1123 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
1124 bool is_read_only = (attributes & READ_ONLY) != 0;
1125 if (lookup.type() == INTERCEPTOR) {
1126 // If the interceptor says the property is there, we
1127 // just return undefined without overwriting the property.
1128 // Otherwise, we continue to setting the property.
1129 if (attributes != ABSENT) {
1130 // Check if the existing property conflicts with regards to const.
1131 if (is_local && (is_read_only || is_const_property)) {
1132 const char* type = (is_read_only) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001133 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001134 };
1135 // The property already exists without conflicting: Go to
1136 // the next declaration.
1137 continue;
1138 }
1139 // Fall-through and introduce the absent property by using
1140 // SetProperty.
1141 } else {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001142 // For const properties, we treat a callback with this name
1143 // even in the prototype as a conflicting declaration.
1144 if (is_const_property && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001145 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001146 }
1147 // Otherwise, we check for locally conflicting declarations.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001148 if (is_local && (is_read_only || is_const_property)) {
1149 const char* type = (is_read_only) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001150 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001151 }
1152 // The property already exists without conflicting: Go to
1153 // the next declaration.
1154 continue;
1155 }
1156 }
1157 } else {
1158 // Copy the function and update its context. Use it as value.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001159 Handle<SharedFunctionInfo> shared =
1160 Handle<SharedFunctionInfo>::cast(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001161 Handle<JSFunction> function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001162 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
1163 context,
1164 TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001165 value = function;
1166 }
1167
1168 LookupResult lookup;
1169 global->LocalLookup(*name, &lookup);
1170
1171 PropertyAttributes attributes = is_const_property
1172 ? static_cast<PropertyAttributes>(base | READ_ONLY)
1173 : base;
1174
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001175 // There's a local property that we need to overwrite because
1176 // we're either declaring a function or there's an interceptor
1177 // that claims the property is absent.
1178 //
1179 // Check for conflicting re-declarations. We cannot have
1180 // conflicting types in case of intercepted properties because
1181 // they are absent.
1182 if (lookup.IsProperty() &&
1183 (lookup.type() != INTERCEPTOR) &&
1184 (lookup.IsReadOnly() || is_const_property)) {
1185 const char* type = (lookup.IsReadOnly()) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001186 return ThrowRedeclarationError(isolate, type, name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001187 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001188
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001189 // Safari does not allow the invocation of callback setters for
1190 // function declarations. To mimic this behavior, we do not allow
1191 // the invocation of setters for function values. This makes a
1192 // difference for global functions with the same names as event
1193 // handlers such as "function onload() {}". Firefox does call the
1194 // onload setter in those case and Safari does not. We follow
1195 // Safari for compatibility.
1196 if (value->IsJSFunction()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001197 // Do not change DONT_DELETE to false from true.
1198 if (lookup.IsProperty() && (lookup.type() != INTERCEPTOR)) {
1199 attributes = static_cast<PropertyAttributes>(
1200 attributes | (lookup.GetAttributes() & DONT_DELETE));
1201 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001202 RETURN_IF_EMPTY_HANDLE(isolate,
1203 SetLocalPropertyIgnoreAttributes(global,
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001204 name,
1205 value,
1206 attributes));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001207 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001208 RETURN_IF_EMPTY_HANDLE(isolate,
1209 SetProperty(global,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001210 name,
1211 value,
1212 attributes,
1213 strict_mode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001214 }
1215 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001216
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001217 ASSERT(!isolate->has_pending_exception());
1218 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001219}
1220
1221
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001222RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001223 HandleScope scope(isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001224 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001225
ager@chromium.org7c537e22008-10-16 08:43:32 +00001226 CONVERT_ARG_CHECKED(Context, context, 0);
1227 Handle<String> name(String::cast(args[1]));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001228 PropertyAttributes mode =
ager@chromium.org7c537e22008-10-16 08:43:32 +00001229 static_cast<PropertyAttributes>(Smi::cast(args[2])->value());
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001230 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001231 Handle<Object> initial_value(args[3], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001232
1233 // Declarations are always done in the function context.
1234 context = Handle<Context>(context->fcontext());
1235
1236 int index;
1237 PropertyAttributes attributes;
1238 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001239 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001240 context->Lookup(name, flags, &index, &attributes);
1241
1242 if (attributes != ABSENT) {
1243 // The name was declared before; check for conflicting
1244 // re-declarations: This is similar to the code in parser.cc in
1245 // the AstBuildingParser::Declare function.
1246 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
1247 // Functions are not read-only.
1248 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
1249 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001250 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001251 }
1252
1253 // Initialize it if necessary.
1254 if (*initial_value != NULL) {
1255 if (index >= 0) {
1256 // The variable or constant context slot should always be in
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001257 // the function context or the arguments object.
1258 if (holder->IsContext()) {
1259 ASSERT(holder.is_identical_to(context));
1260 if (((attributes & READ_ONLY) == 0) ||
1261 context->get(index)->IsTheHole()) {
1262 context->set(index, *initial_value);
1263 }
1264 } else {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001265 // The holder is an arguments object.
1266 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001267 Handle<Object> result = SetElement(arguments, index, initial_value,
1268 kNonStrictMode);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001269 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001270 }
1271 } else {
1272 // Slow case: The property is not in the FixedArray part of the context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001273 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001274 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001275 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001276 SetProperty(context_ext, name, initial_value,
1277 mode, kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001278 }
1279 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001280
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001281 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001282 // The property is not in the function context. It needs to be
1283 // "declared" in the function context's extension context, or in the
1284 // global context.
1285 Handle<JSObject> context_ext;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001286 if (context->has_extension()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001287 // The function context's extension context exists - use it.
1288 context_ext = Handle<JSObject>(context->extension());
1289 } else {
1290 // The function context's extension context does not exists - allocate
1291 // it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001292 context_ext = isolate->factory()->NewJSObject(
1293 isolate->context_extension_function());
ager@chromium.org7c537e22008-10-16 08:43:32 +00001294 // And store it in the extension slot.
1295 context->set_extension(*context_ext);
1296 }
1297 ASSERT(*context_ext != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001298
ager@chromium.org7c537e22008-10-16 08:43:32 +00001299 // Declare the property by setting it to the initial value if provided,
1300 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
1301 // constant declarations).
1302 ASSERT(!context_ext->HasLocalProperty(*name));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001303 Handle<Object> value(isolate->heap()->undefined_value(), isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001304 if (*initial_value != NULL) value = initial_value;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001305 // Declaring a const context slot is a conflicting declaration if
1306 // there is a callback with that name in a prototype. It is
1307 // allowed to introduce const variables in
1308 // JSContextExtensionObjects. They are treated specially in
1309 // SetProperty and no setters are invoked for those since they are
1310 // not real JSObjects.
1311 if (initial_value->IsTheHole() &&
1312 !context_ext->IsJSContextExtensionObject()) {
1313 LookupResult lookup;
1314 context_ext->Lookup(*name, &lookup);
1315 if (lookup.IsProperty() && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001316 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001317 }
1318 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001319 RETURN_IF_EMPTY_HANDLE(isolate,
1320 SetProperty(context_ext, name, value, mode,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001321 kNonStrictMode));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001322 }
1323
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001324 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001325}
1326
1327
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001328RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001329 NoHandleAllocation nha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001330 // args[0] == name
1331 // args[1] == strict_mode
1332 // args[2] == value (optional)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001333
1334 // Determine if we need to assign to the variable if it already
1335 // exists (based on the number of arguments).
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001336 RUNTIME_ASSERT(args.length() == 2 || args.length() == 3);
1337 bool assign = args.length() == 3;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001338
1339 CONVERT_ARG_CHECKED(String, name, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001340 GlobalObject* global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001341 RUNTIME_ASSERT(args[1]->IsSmi());
1342 StrictModeFlag strict_mode =
1343 static_cast<StrictModeFlag>(Smi::cast(args[1])->value());
1344 ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001345
1346 // According to ECMA-262, section 12.2, page 62, the property must
1347 // not be deletable.
1348 PropertyAttributes attributes = DONT_DELETE;
1349
1350 // Lookup the property locally in the global object. If it isn't
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001351 // there, there is a property with this name in the prototype chain.
1352 // We follow Safari and Firefox behavior and only set the property
1353 // locally if there is an explicit initialization value that we have
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001354 // to assign to the property.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001355 // Note that objects can have hidden prototypes, so we need to traverse
1356 // the whole chain of hidden prototypes to do a 'local' lookup.
1357 JSObject* real_holder = global;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001358 LookupResult lookup;
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001359 while (true) {
1360 real_holder->LocalLookup(*name, &lookup);
1361 if (lookup.IsProperty()) {
1362 // Determine if this is a redeclaration of something read-only.
1363 if (lookup.IsReadOnly()) {
1364 // If we found readonly property on one of hidden prototypes,
1365 // just shadow it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001366 if (real_holder != isolate->context()->global()) break;
1367 return ThrowRedeclarationError(isolate, "const", name);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001368 }
1369
1370 // Determine if this is a redeclaration of an intercepted read-only
1371 // property and figure out if the property exists at all.
1372 bool found = true;
1373 PropertyType type = lookup.type();
1374 if (type == INTERCEPTOR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001375 HandleScope handle_scope(isolate);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001376 Handle<JSObject> holder(real_holder);
1377 PropertyAttributes intercepted = holder->GetPropertyAttribute(*name);
1378 real_holder = *holder;
1379 if (intercepted == ABSENT) {
1380 // The interceptor claims the property isn't there. We need to
1381 // make sure to introduce it.
1382 found = false;
1383 } else if ((intercepted & READ_ONLY) != 0) {
1384 // The property is present, but read-only. Since we're trying to
1385 // overwrite it with a variable declaration we must throw a
1386 // re-declaration error. However if we found readonly property
1387 // on one of hidden prototypes, just shadow it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001388 if (real_holder != isolate->context()->global()) break;
1389 return ThrowRedeclarationError(isolate, "const", name);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001390 }
1391 }
1392
1393 if (found && !assign) {
1394 // The global property is there and we're not assigning any value
1395 // to it. Just return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001396 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001397 }
1398
1399 // Assign the value (or undefined) to the property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001400 Object* value = (assign) ? args[2] : isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001401 return real_holder->SetProperty(
1402 &lookup, *name, value, attributes, strict_mode);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001403 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001404
1405 Object* proto = real_holder->GetPrototype();
1406 if (!proto->IsJSObject())
1407 break;
1408
1409 if (!JSObject::cast(proto)->map()->is_hidden_prototype())
1410 break;
1411
1412 real_holder = JSObject::cast(proto);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001413 }
1414
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001415 global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001416 if (assign) {
1417 return global->SetProperty(*name, args[2], attributes, strict_mode);
1418 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001419 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001420}
1421
1422
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001423RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001424 // All constants are declared with an initial value. The name
1425 // of the constant is the first argument and the initial value
1426 // is the second.
1427 RUNTIME_ASSERT(args.length() == 2);
1428 CONVERT_ARG_CHECKED(String, name, 0);
1429 Handle<Object> value = args.at<Object>(1);
1430
1431 // Get the current global object from top.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001432 GlobalObject* global = isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001433
1434 // According to ECMA-262, section 12.2, page 62, the property must
1435 // not be deletable. Since it's a const, it must be READ_ONLY too.
1436 PropertyAttributes attributes =
1437 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
1438
1439 // Lookup the property locally in the global object. If it isn't
1440 // there, we add the property and take special precautions to always
1441 // add it as a local property even in case of callbacks in the
1442 // prototype chain (this rules out using SetProperty).
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001443 // We use SetLocalPropertyIgnoreAttributes instead
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001444 LookupResult lookup;
1445 global->LocalLookup(*name, &lookup);
1446 if (!lookup.IsProperty()) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001447 return global->SetLocalPropertyIgnoreAttributes(*name,
1448 *value,
1449 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001450 }
1451
1452 // Determine if this is a redeclaration of something not
1453 // read-only. In case the result is hidden behind an interceptor we
1454 // need to ask it for the property attributes.
1455 if (!lookup.IsReadOnly()) {
1456 if (lookup.type() != INTERCEPTOR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001457 return ThrowRedeclarationError(isolate, "var", name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001458 }
1459
1460 PropertyAttributes intercepted = global->GetPropertyAttribute(*name);
1461
1462 // Throw re-declaration error if the intercepted property is present
1463 // but not read-only.
1464 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001465 return ThrowRedeclarationError(isolate, "var", name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001466 }
1467
1468 // Restore global object from context (in case of GC) and continue
1469 // with setting the value because the property is either absent or
1470 // read-only. We also have to do redo the lookup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001471 HandleScope handle_scope(isolate);
1472 Handle<GlobalObject> global(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001473
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001474 // BUG 1213575: Handle the case where we have to set a read-only
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001475 // property through an interceptor and only do it if it's
1476 // uninitialized, e.g. the hole. Nirk...
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001477 // Passing non-strict mode because the property is writable.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001478 RETURN_IF_EMPTY_HANDLE(isolate,
1479 SetProperty(global,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001480 name,
1481 value,
1482 attributes,
1483 kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001484 return *value;
1485 }
1486
1487 // Set the value, but only we're assigning the initial value to a
1488 // constant. For now, we determine this by checking if the
1489 // current value is the hole.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001490 // Strict mode handling not needed (const disallowed in strict mode).
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001491 PropertyType type = lookup.type();
1492 if (type == FIELD) {
1493 FixedArray* properties = global->properties();
1494 int index = lookup.GetFieldIndex();
1495 if (properties->get(index)->IsTheHole()) {
1496 properties->set(index, *value);
1497 }
1498 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001499 if (global->GetNormalizedProperty(&lookup)->IsTheHole()) {
1500 global->SetNormalizedProperty(&lookup, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001501 }
1502 } else {
1503 // Ignore re-initialization of constants that have already been
1504 // assigned a function value.
1505 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
1506 }
1507
1508 // Use the set value as the result of the operation.
1509 return *value;
1510}
1511
1512
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001513RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001514 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001515 ASSERT(args.length() == 3);
1516
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001517 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001518 ASSERT(!value->IsTheHole());
1519 CONVERT_ARG_CHECKED(Context, context, 1);
1520 Handle<String> name(String::cast(args[2]));
1521
1522 // Initializations are always done in the function context.
1523 context = Handle<Context>(context->fcontext());
1524
1525 int index;
1526 PropertyAttributes attributes;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001527 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001528 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001529 context->Lookup(name, flags, &index, &attributes);
1530
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001531 // In most situations, the property introduced by the const
1532 // declaration should be present in the context extension object.
1533 // However, because declaration and initialization are separate, the
1534 // property might have been deleted (if it was introduced by eval)
1535 // before we reach the initialization point.
1536 //
1537 // Example:
1538 //
1539 // function f() { eval("delete x; const x;"); }
1540 //
1541 // In that case, the initialization behaves like a normal assignment
1542 // to property 'x'.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001543 if (index >= 0) {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001544 // Property was found in a context.
1545 if (holder->IsContext()) {
1546 // The holder cannot be the function context. If it is, there
1547 // should have been a const redeclaration error when declaring
1548 // the const property.
1549 ASSERT(!holder.is_identical_to(context));
1550 if ((attributes & READ_ONLY) == 0) {
1551 Handle<Context>::cast(holder)->set(index, *value);
1552 }
1553 } else {
1554 // The holder is an arguments object.
1555 ASSERT((attributes & READ_ONLY) == 0);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001556 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001557 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001558 isolate,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001559 SetElement(arguments, index, value, kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001560 }
1561 return *value;
1562 }
1563
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001564 // The property could not be found, we introduce it in the global
1565 // context.
1566 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001567 Handle<JSObject> global = Handle<JSObject>(
1568 isolate->context()->global());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001569 // Strict mode not needed (const disallowed in strict mode).
1570 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001571 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001572 SetProperty(global, name, value, NONE, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001573 return *value;
1574 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001575
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001576 // The property was present in a context extension object.
1577 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001578
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001579 if (*context_ext == context->extension()) {
1580 // This is the property that was introduced by the const
1581 // declaration. Set it if it hasn't been set before. NOTE: We
1582 // cannot use GetProperty() to get the current value as it
1583 // 'unholes' the value.
1584 LookupResult lookup;
1585 context_ext->LocalLookupRealNamedProperty(*name, &lookup);
1586 ASSERT(lookup.IsProperty()); // the property was declared
1587 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
1588
1589 PropertyType type = lookup.type();
1590 if (type == FIELD) {
1591 FixedArray* properties = context_ext->properties();
1592 int index = lookup.GetFieldIndex();
1593 if (properties->get(index)->IsTheHole()) {
1594 properties->set(index, *value);
1595 }
1596 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001597 if (context_ext->GetNormalizedProperty(&lookup)->IsTheHole()) {
1598 context_ext->SetNormalizedProperty(&lookup, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001599 }
1600 } else {
1601 // We should not reach here. Any real, named property should be
1602 // either a field or a dictionary slot.
1603 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001604 }
1605 } else {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001606 // The property was found in a different context extension object.
1607 // Set it if it is not a read-only property.
1608 if ((attributes & READ_ONLY) == 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001609 // Strict mode not needed (const disallowed in strict mode).
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001610 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001611 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001612 SetProperty(context_ext, name, value, attributes, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001613 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001614 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001615
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001616 return *value;
1617}
1618
1619
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001620RUNTIME_FUNCTION(MaybeObject*,
1621 Runtime_OptimizeObjectForAddingMultipleProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001622 HandleScope scope(isolate);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001623 ASSERT(args.length() == 2);
1624 CONVERT_ARG_CHECKED(JSObject, object, 0);
1625 CONVERT_SMI_CHECKED(properties, args[1]);
1626 if (object->HasFastProperties()) {
1627 NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
1628 }
1629 return *object;
1630}
1631
1632
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001633RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExec) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001634 HandleScope scope(isolate);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001635 ASSERT(args.length() == 4);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001636 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
1637 CONVERT_ARG_CHECKED(String, subject, 1);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001638 // Due to the way the JS calls are constructed this must be less than the
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001639 // length of a string, i.e. it is always a Smi. We check anyway for security.
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001640 CONVERT_SMI_CHECKED(index, args[2]);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001641 CONVERT_ARG_CHECKED(JSArray, last_match_info, 3);
ager@chromium.org41826e72009-03-30 13:30:57 +00001642 RUNTIME_ASSERT(last_match_info->HasFastElements());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001643 RUNTIME_ASSERT(index >= 0);
1644 RUNTIME_ASSERT(index <= subject->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001645 isolate->counters()->regexp_entry_runtime()->Increment();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001646 Handle<Object> result = RegExpImpl::Exec(regexp,
1647 subject,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001648 index,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001649 last_match_info);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001650 if (result.is_null()) return Failure::Exception();
1651 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001652}
1653
1654
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001655RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpConstructResult) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001656 ASSERT(args.length() == 3);
1657 CONVERT_SMI_CHECKED(elements_count, args[0]);
1658 if (elements_count > JSArray::kMaxFastElementsLength) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001659 return isolate->ThrowIllegalOperation();
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001660 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00001661 Object* new_object;
1662 { MaybeObject* maybe_new_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001663 isolate->heap()->AllocateFixedArrayWithHoles(elements_count);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001664 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1665 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001666 FixedArray* elements = FixedArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001667 { MaybeObject* maybe_new_object = isolate->heap()->AllocateRaw(
1668 JSRegExpResult::kSize, NEW_SPACE, OLD_POINTER_SPACE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001669 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1670 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001671 {
1672 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001673 HandleScope scope(isolate);
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001674 reinterpret_cast<HeapObject*>(new_object)->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001675 set_map(isolate->global_context()->regexp_result_map());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001676 }
1677 JSArray* array = JSArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001678 array->set_properties(isolate->heap()->empty_fixed_array());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001679 array->set_elements(elements);
1680 array->set_length(Smi::FromInt(elements_count));
1681 // Write in-object properties after the length of the array.
1682 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]);
1683 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]);
1684 return array;
1685}
1686
1687
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001688RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpInitializeObject) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00001689 AssertNoAllocation no_alloc;
1690 ASSERT(args.length() == 5);
1691 CONVERT_CHECKED(JSRegExp, regexp, args[0]);
1692 CONVERT_CHECKED(String, source, args[1]);
1693
1694 Object* global = args[2];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001695 if (!global->IsTrue()) global = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001696
1697 Object* ignoreCase = args[3];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001698 if (!ignoreCase->IsTrue()) ignoreCase = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001699
1700 Object* multiline = args[4];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001701 if (!multiline->IsTrue()) multiline = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001702
1703 Map* map = regexp->map();
1704 Object* constructor = map->constructor();
1705 if (constructor->IsJSFunction() &&
1706 JSFunction::cast(constructor)->initial_map() == map) {
1707 // If we still have the original map, set in-object properties directly.
1708 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source);
1709 // TODO(lrn): Consider skipping write barrier on booleans as well.
1710 // Both true and false should be in oldspace at all times.
1711 regexp->InObjectPropertyAtPut(JSRegExp::kGlobalFieldIndex, global);
1712 regexp->InObjectPropertyAtPut(JSRegExp::kIgnoreCaseFieldIndex, ignoreCase);
1713 regexp->InObjectPropertyAtPut(JSRegExp::kMultilineFieldIndex, multiline);
1714 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
1715 Smi::FromInt(0),
1716 SKIP_WRITE_BARRIER);
1717 return regexp;
1718 }
1719
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001720 // Map has changed, so use generic, but slower, method.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001721 PropertyAttributes final =
1722 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
1723 PropertyAttributes writable =
1724 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001725 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +00001726 MaybeObject* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001727 result = regexp->SetLocalPropertyIgnoreAttributes(heap->source_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001728 source,
1729 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001730 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001731 result = regexp->SetLocalPropertyIgnoreAttributes(heap->global_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001732 global,
1733 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001734 ASSERT(!result->IsFailure());
1735 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001736 regexp->SetLocalPropertyIgnoreAttributes(heap->ignore_case_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001737 ignoreCase,
1738 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001739 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001740 result = regexp->SetLocalPropertyIgnoreAttributes(heap->multiline_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001741 multiline,
1742 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001743 ASSERT(!result->IsFailure());
1744 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001745 regexp->SetLocalPropertyIgnoreAttributes(heap->last_index_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001746 Smi::FromInt(0),
1747 writable);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001748 ASSERT(!result->IsFailure());
1749 USE(result);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001750 return regexp;
1751}
1752
1753
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001754RUNTIME_FUNCTION(MaybeObject*, Runtime_FinishArrayPrototypeSetup) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001755 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001756 ASSERT(args.length() == 1);
1757 CONVERT_ARG_CHECKED(JSArray, prototype, 0);
1758 // This is necessary to enable fast checks for absence of elements
1759 // on Array.prototype and below.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001760 prototype->set_elements(isolate->heap()->empty_fixed_array());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001761 return Smi::FromInt(0);
1762}
1763
1764
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001765static Handle<JSFunction> InstallBuiltin(Isolate* isolate,
1766 Handle<JSObject> holder,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001767 const char* name,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001768 Builtins::Name builtin_name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001769 Handle<String> key = isolate->factory()->LookupAsciiSymbol(name);
1770 Handle<Code> code(isolate->builtins()->builtin(builtin_name));
1771 Handle<JSFunction> optimized =
1772 isolate->factory()->NewFunction(key,
1773 JS_OBJECT_TYPE,
1774 JSObject::kHeaderSize,
1775 code,
1776 false);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001777 optimized->shared()->DontAdaptArguments();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001778 SetProperty(holder, key, optimized, NONE, kStrictMode);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001779 return optimized;
1780}
1781
1782
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001783RUNTIME_FUNCTION(MaybeObject*, Runtime_SpecialArrayFunctions) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001784 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001785 ASSERT(args.length() == 1);
1786 CONVERT_ARG_CHECKED(JSObject, holder, 0);
1787
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001788 InstallBuiltin(isolate, holder, "pop", Builtins::kArrayPop);
1789 InstallBuiltin(isolate, holder, "push", Builtins::kArrayPush);
1790 InstallBuiltin(isolate, holder, "shift", Builtins::kArrayShift);
1791 InstallBuiltin(isolate, holder, "unshift", Builtins::kArrayUnshift);
1792 InstallBuiltin(isolate, holder, "slice", Builtins::kArraySlice);
1793 InstallBuiltin(isolate, holder, "splice", Builtins::kArraySplice);
1794 InstallBuiltin(isolate, holder, "concat", Builtins::kArrayConcat);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001795
1796 return *holder;
1797}
1798
1799
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001800RUNTIME_FUNCTION(MaybeObject*, Runtime_GetGlobalReceiver) {
ager@chromium.org357bf652010-04-12 11:30:10 +00001801 // Returns a real global receiver, not one of builtins object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001802 Context* global_context =
1803 isolate->context()->global()->global_context();
ager@chromium.org357bf652010-04-12 11:30:10 +00001804 return global_context->global()->global_receiver();
1805}
1806
1807
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001808RUNTIME_FUNCTION(MaybeObject*, Runtime_MaterializeRegExpLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001809 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001810 ASSERT(args.length() == 4);
1811 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
1812 int index = Smi::cast(args[1])->value();
1813 Handle<String> pattern = args.at<String>(2);
1814 Handle<String> flags = args.at<String>(3);
1815
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001816 // Get the RegExp function from the context in the literals array.
1817 // This is the RegExp function from the context in which the
1818 // function was created. We do not use the RegExp function from the
1819 // current global context because this might be the RegExp function
1820 // from another context which we should not have access to.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001821 Handle<JSFunction> constructor =
ager@chromium.org236ad962008-09-25 09:45:57 +00001822 Handle<JSFunction>(
1823 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001824 // Compute the regular expression literal.
1825 bool has_pending_exception;
1826 Handle<Object> regexp =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001827 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
1828 &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001829 if (has_pending_exception) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001830 ASSERT(isolate->has_pending_exception());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001831 return Failure::Exception();
1832 }
1833 literals->set(index, *regexp);
1834 return *regexp;
1835}
1836
1837
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001838RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001839 NoHandleAllocation ha;
1840 ASSERT(args.length() == 1);
1841
1842 CONVERT_CHECKED(JSFunction, f, args[0]);
1843 return f->shared()->name();
1844}
1845
1846
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001847RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetName) {
ager@chromium.org236ad962008-09-25 09:45:57 +00001848 NoHandleAllocation ha;
1849 ASSERT(args.length() == 2);
1850
1851 CONVERT_CHECKED(JSFunction, f, args[0]);
1852 CONVERT_CHECKED(String, name, args[1]);
1853 f->shared()->set_name(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001854 return isolate->heap()->undefined_value();
ager@chromium.org236ad962008-09-25 09:45:57 +00001855}
1856
1857
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001858RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionRemovePrototype) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001859 NoHandleAllocation ha;
1860 ASSERT(args.length() == 1);
1861
1862 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001863 Object* obj = f->RemovePrototype();
1864 if (obj->IsFailure()) return obj;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001865
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001866 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001867}
1868
1869
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001870RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001871 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001872 ASSERT(args.length() == 1);
1873
1874 CONVERT_CHECKED(JSFunction, fun, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001875 Handle<Object> script = Handle<Object>(fun->shared()->script(), isolate);
1876 if (!script->IsScript()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001877
1878 return *GetScriptWrapper(Handle<Script>::cast(script));
1879}
1880
1881
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001882RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetSourceCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001883 NoHandleAllocation ha;
1884 ASSERT(args.length() == 1);
1885
1886 CONVERT_CHECKED(JSFunction, f, args[0]);
1887 return f->shared()->GetSourceCode();
1888}
1889
1890
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001891RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScriptSourcePosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001892 NoHandleAllocation ha;
1893 ASSERT(args.length() == 1);
1894
1895 CONVERT_CHECKED(JSFunction, fun, args[0]);
1896 int pos = fun->shared()->start_position();
1897 return Smi::FromInt(pos);
1898}
1899
1900
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001901RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetPositionForOffset) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001902 ASSERT(args.length() == 2);
1903
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001904 CONVERT_CHECKED(Code, code, args[0]);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001905 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
1906
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001907 RUNTIME_ASSERT(0 <= offset && offset < code->Size());
1908
1909 Address pc = code->address() + offset;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001910 return Smi::FromInt(code->SourcePosition(pc));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001911}
1912
1913
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001914RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetInstanceClassName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001915 NoHandleAllocation ha;
1916 ASSERT(args.length() == 2);
1917
1918 CONVERT_CHECKED(JSFunction, fun, args[0]);
1919 CONVERT_CHECKED(String, name, args[1]);
1920 fun->SetInstanceClassName(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001921 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001922}
1923
1924
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001925RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetLength) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001926 NoHandleAllocation ha;
1927 ASSERT(args.length() == 2);
1928
1929 CONVERT_CHECKED(JSFunction, fun, args[0]);
1930 CONVERT_CHECKED(Smi, length, args[1]);
1931 fun->shared()->set_length(length->value());
1932 return length;
1933}
1934
1935
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001936RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetPrototype) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001937 NoHandleAllocation ha;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001938 ASSERT(args.length() == 2);
1939
1940 CONVERT_CHECKED(JSFunction, fun, args[0]);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001941 ASSERT(fun->should_have_prototype());
lrn@chromium.org303ada72010-10-27 09:33:13 +00001942 Object* obj;
1943 { MaybeObject* maybe_obj =
1944 Accessors::FunctionSetPrototype(fun, args[1], NULL);
1945 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1946 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001947 return args[0]; // return TOS
1948}
1949
1950
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001951RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsAPIFunction) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001952 NoHandleAllocation ha;
1953 ASSERT(args.length() == 1);
1954
1955 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001956 return f->shared()->IsApiFunction() ? isolate->heap()->true_value()
1957 : isolate->heap()->false_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001958}
1959
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001960
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001961RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsBuiltin) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001962 NoHandleAllocation ha;
1963 ASSERT(args.length() == 1);
1964
1965 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001966 return f->IsBuiltin() ? isolate->heap()->true_value() :
1967 isolate->heap()->false_value();
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001968}
1969
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001970
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001971RUNTIME_FUNCTION(MaybeObject*, Runtime_SetCode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001972 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001973 ASSERT(args.length() == 2);
1974
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001975 CONVERT_ARG_CHECKED(JSFunction, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001976 Handle<Object> code = args.at<Object>(1);
1977
1978 Handle<Context> context(target->context());
1979
1980 if (!code->IsNull()) {
1981 RUNTIME_ASSERT(code->IsJSFunction());
1982 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001983 Handle<SharedFunctionInfo> shared(fun->shared());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001984
1985 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001986 return Failure::Exception();
1987 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001988 // Since we don't store the source for this we should never
1989 // optimize this.
1990 shared->code()->set_optimizable(false);
1991
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001992 // Set the code, scope info, formal parameter count,
1993 // and the length of the target function.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00001994 target->shared()->set_code(shared->code());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001995 target->ReplaceCode(shared->code());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001996 target->shared()->set_scope_info(shared->scope_info());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001997 target->shared()->set_length(shared->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001998 target->shared()->set_formal_parameter_count(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001999 shared->formal_parameter_count());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002000 // Set the source code of the target function to undefined.
2001 // SetCode is only used for built-in constructors like String,
2002 // Array, and Object, and some web code
2003 // doesn't like seeing source code for constructors.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002004 target->shared()->set_script(isolate->heap()->undefined_value());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002005 target->shared()->code()->set_optimizable(false);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00002006 // Clear the optimization hints related to the compiled code as these are no
2007 // longer valid when the code is overwritten.
2008 target->shared()->ClearThisPropertyAssignmentsInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002009 context = Handle<Context>(fun->context());
2010
2011 // Make sure we get a fresh copy of the literal vector to avoid
2012 // cross context contamination.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002013 int number_of_literals = fun->NumberOfLiterals();
2014 Handle<FixedArray> literals =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002015 isolate->factory()->NewFixedArray(number_of_literals, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002016 if (number_of_literals > 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002017 // Insert the object, regexp and array functions in the literals
2018 // array prefix. These are the functions that will be used when
2019 // creating object, regexp and array literals.
ager@chromium.org236ad962008-09-25 09:45:57 +00002020 literals->set(JSFunction::kLiteralGlobalContextIndex,
2021 context->global_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002022 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002023 // It's okay to skip the write barrier here because the literals
2024 // are guaranteed to be in old space.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00002025 target->set_literals(*literals, SKIP_WRITE_BARRIER);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002026 target->set_next_function_link(isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002027 }
2028
2029 target->set_context(*context);
2030 return *target;
2031}
2032
2033
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002034RUNTIME_FUNCTION(MaybeObject*, Runtime_SetExpectedNumberOfProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002035 HandleScope scope(isolate);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002036 ASSERT(args.length() == 2);
2037 CONVERT_ARG_CHECKED(JSFunction, function, 0);
2038 CONVERT_SMI_CHECKED(num, args[1]);
2039 RUNTIME_ASSERT(num >= 0);
2040 SetExpectedNofProperties(function, num);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002041 return isolate->heap()->undefined_value();
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002042}
2043
2044
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002045MUST_USE_RESULT static MaybeObject* CharFromCode(Isolate* isolate,
2046 Object* char_code) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002047 uint32_t code;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002048 if (char_code->ToArrayIndex(&code)) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002049 if (code <= 0xffff) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002050 return isolate->heap()->LookupSingleCharacterStringFromCode(code);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002051 }
2052 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002053 return isolate->heap()->empty_string();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002054}
2055
2056
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002057RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCharCodeAt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002058 NoHandleAllocation ha;
2059 ASSERT(args.length() == 2);
2060
2061 CONVERT_CHECKED(String, subject, args[0]);
2062 Object* index = args[1];
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002063 RUNTIME_ASSERT(index->IsNumber());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002064
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002065 uint32_t i = 0;
2066 if (index->IsSmi()) {
2067 int value = Smi::cast(index)->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002068 if (value < 0) return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002069 i = value;
2070 } else {
2071 ASSERT(index->IsHeapNumber());
2072 double value = HeapNumber::cast(index)->value();
2073 i = static_cast<uint32_t>(DoubleToInteger(value));
kasperl@chromium.org74e4e5e2010-01-25 10:15:52 +00002074 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002075
2076 // Flatten the string. If someone wants to get a char at an index
2077 // in a cons string, it is likely that more indices will be
2078 // accessed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002079 Object* flat;
2080 { MaybeObject* maybe_flat = subject->TryFlatten();
2081 if (!maybe_flat->ToObject(&flat)) return maybe_flat;
2082 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002083 subject = String::cast(flat);
2084
2085 if (i >= static_cast<uint32_t>(subject->length())) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002086 return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002087 }
2088
2089 return Smi::FromInt(subject->Get(i));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002090}
2091
2092
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002093RUNTIME_FUNCTION(MaybeObject*, Runtime_CharFromCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002094 NoHandleAllocation ha;
2095 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002096 return CharFromCode(isolate, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002097}
2098
lrn@chromium.org25156de2010-04-06 13:10:27 +00002099
2100class FixedArrayBuilder {
2101 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002102 explicit FixedArrayBuilder(Isolate* isolate, int initial_capacity)
2103 : array_(isolate->factory()->NewFixedArrayWithHoles(initial_capacity)),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002104 length_(0) {
2105 // Require a non-zero initial size. Ensures that doubling the size to
2106 // extend the array will work.
2107 ASSERT(initial_capacity > 0);
2108 }
2109
2110 explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
2111 : array_(backing_store),
2112 length_(0) {
2113 // Require a non-zero initial size. Ensures that doubling the size to
2114 // extend the array will work.
2115 ASSERT(backing_store->length() > 0);
2116 }
2117
2118 bool HasCapacity(int elements) {
2119 int length = array_->length();
2120 int required_length = length_ + elements;
2121 return (length >= required_length);
2122 }
2123
2124 void EnsureCapacity(int elements) {
2125 int length = array_->length();
2126 int required_length = length_ + elements;
2127 if (length < required_length) {
2128 int new_length = length;
2129 do {
2130 new_length *= 2;
2131 } while (new_length < required_length);
2132 Handle<FixedArray> extended_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002133 array_->GetIsolate()->factory()->NewFixedArrayWithHoles(new_length);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002134 array_->CopyTo(0, *extended_array, 0, length_);
2135 array_ = extended_array;
2136 }
2137 }
2138
2139 void Add(Object* value) {
2140 ASSERT(length_ < capacity());
2141 array_->set(length_, value);
2142 length_++;
2143 }
2144
2145 void Add(Smi* value) {
2146 ASSERT(length_ < capacity());
2147 array_->set(length_, value);
2148 length_++;
2149 }
2150
2151 Handle<FixedArray> array() {
2152 return array_;
2153 }
2154
2155 int length() {
2156 return length_;
2157 }
2158
2159 int capacity() {
2160 return array_->length();
2161 }
2162
2163 Handle<JSArray> ToJSArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002164 Handle<JSArray> result_array = FACTORY->NewJSArrayWithElements(array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002165 result_array->set_length(Smi::FromInt(length_));
2166 return result_array;
2167 }
2168
2169 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
2170 target_array->set_elements(*array_);
2171 target_array->set_length(Smi::FromInt(length_));
2172 return target_array;
2173 }
2174
2175 private:
2176 Handle<FixedArray> array_;
2177 int length_;
2178};
2179
2180
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002181// Forward declarations.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002182const int kStringBuilderConcatHelperLengthBits = 11;
2183const int kStringBuilderConcatHelperPositionBits = 19;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002184
2185template <typename schar>
2186static inline void StringBuilderConcatHelper(String*,
2187 schar*,
2188 FixedArray*,
2189 int);
2190
lrn@chromium.org25156de2010-04-06 13:10:27 +00002191typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
2192 StringBuilderSubstringLength;
2193typedef BitField<int,
2194 kStringBuilderConcatHelperLengthBits,
2195 kStringBuilderConcatHelperPositionBits>
2196 StringBuilderSubstringPosition;
2197
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002198
2199class ReplacementStringBuilder {
2200 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002201 ReplacementStringBuilder(Heap* heap,
2202 Handle<String> subject,
2203 int estimated_part_count)
2204 : heap_(heap),
2205 array_builder_(heap->isolate(), estimated_part_count),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002206 subject_(subject),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002207 character_count_(0),
ager@chromium.org5ec48922009-05-05 07:25:34 +00002208 is_ascii_(subject->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002209 // Require a non-zero initial size. Ensures that doubling the size to
2210 // extend the array will work.
2211 ASSERT(estimated_part_count > 0);
2212 }
2213
lrn@chromium.org25156de2010-04-06 13:10:27 +00002214 static inline void AddSubjectSlice(FixedArrayBuilder* builder,
2215 int from,
2216 int to) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002217 ASSERT(from >= 0);
2218 int length = to - from;
2219 ASSERT(length > 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002220 if (StringBuilderSubstringLength::is_valid(length) &&
2221 StringBuilderSubstringPosition::is_valid(from)) {
2222 int encoded_slice = StringBuilderSubstringLength::encode(length) |
2223 StringBuilderSubstringPosition::encode(from);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002224 builder->Add(Smi::FromInt(encoded_slice));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002225 } else {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002226 // Otherwise encode as two smis.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002227 builder->Add(Smi::FromInt(-length));
2228 builder->Add(Smi::FromInt(from));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002229 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00002230 }
2231
2232
2233 void EnsureCapacity(int elements) {
2234 array_builder_.EnsureCapacity(elements);
2235 }
2236
2237
2238 void AddSubjectSlice(int from, int to) {
2239 AddSubjectSlice(&array_builder_, from, to);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002240 IncrementCharacterCount(to - from);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002241 }
2242
2243
2244 void AddString(Handle<String> string) {
2245 int length = string->length();
2246 ASSERT(length > 0);
2247 AddElement(*string);
ager@chromium.org5ec48922009-05-05 07:25:34 +00002248 if (!string->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002249 is_ascii_ = false;
2250 }
2251 IncrementCharacterCount(length);
2252 }
2253
2254
2255 Handle<String> ToString() {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002256 if (array_builder_.length() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002257 return heap_->isolate()->factory()->empty_string();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002258 }
2259
2260 Handle<String> joined_string;
2261 if (is_ascii_) {
2262 joined_string = NewRawAsciiString(character_count_);
2263 AssertNoAllocation no_alloc;
2264 SeqAsciiString* seq = SeqAsciiString::cast(*joined_string);
2265 char* char_buffer = seq->GetChars();
2266 StringBuilderConcatHelper(*subject_,
2267 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002268 *array_builder_.array(),
2269 array_builder_.length());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002270 } else {
2271 // Non-ASCII.
2272 joined_string = NewRawTwoByteString(character_count_);
2273 AssertNoAllocation no_alloc;
2274 SeqTwoByteString* seq = SeqTwoByteString::cast(*joined_string);
2275 uc16* char_buffer = seq->GetChars();
2276 StringBuilderConcatHelper(*subject_,
2277 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002278 *array_builder_.array(),
2279 array_builder_.length());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002280 }
2281 return joined_string;
2282 }
2283
2284
2285 void IncrementCharacterCount(int by) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002286 if (character_count_ > String::kMaxLength - by) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002287 V8::FatalProcessOutOfMemory("String.replace result too large.");
2288 }
2289 character_count_ += by;
2290 }
2291
lrn@chromium.org25156de2010-04-06 13:10:27 +00002292 Handle<JSArray> GetParts() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002293 return array_builder_.ToJSArray();
lrn@chromium.org25156de2010-04-06 13:10:27 +00002294 }
kmillikin@chromium.orgd9825192010-03-30 08:36:16 +00002295
lrn@chromium.org25156de2010-04-06 13:10:27 +00002296 private:
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002297 Handle<String> NewRawAsciiString(int size) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002298 CALL_HEAP_FUNCTION(heap_->isolate(),
2299 heap_->AllocateRawAsciiString(size), String);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002300 }
2301
2302
2303 Handle<String> NewRawTwoByteString(int size) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002304 CALL_HEAP_FUNCTION(heap_->isolate(),
2305 heap_->AllocateRawTwoByteString(size), String);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002306 }
2307
2308
2309 void AddElement(Object* element) {
2310 ASSERT(element->IsSmi() || element->IsString());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002311 ASSERT(array_builder_.capacity() > array_builder_.length());
2312 array_builder_.Add(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002313 }
2314
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002315 Heap* heap_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002316 FixedArrayBuilder array_builder_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002317 Handle<String> subject_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002318 int character_count_;
2319 bool is_ascii_;
2320};
2321
2322
2323class CompiledReplacement {
2324 public:
2325 CompiledReplacement()
2326 : parts_(1), replacement_substrings_(0) {}
2327
2328 void Compile(Handle<String> replacement,
2329 int capture_count,
2330 int subject_length);
2331
2332 void Apply(ReplacementStringBuilder* builder,
2333 int match_from,
2334 int match_to,
2335 Handle<JSArray> last_match_info);
2336
2337 // Number of distinct parts of the replacement pattern.
2338 int parts() {
2339 return parts_.length();
2340 }
2341 private:
2342 enum PartType {
2343 SUBJECT_PREFIX = 1,
2344 SUBJECT_SUFFIX,
2345 SUBJECT_CAPTURE,
2346 REPLACEMENT_SUBSTRING,
2347 REPLACEMENT_STRING,
2348
2349 NUMBER_OF_PART_TYPES
2350 };
2351
2352 struct ReplacementPart {
2353 static inline ReplacementPart SubjectMatch() {
2354 return ReplacementPart(SUBJECT_CAPTURE, 0);
2355 }
2356 static inline ReplacementPart SubjectCapture(int capture_index) {
2357 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
2358 }
2359 static inline ReplacementPart SubjectPrefix() {
2360 return ReplacementPart(SUBJECT_PREFIX, 0);
2361 }
2362 static inline ReplacementPart SubjectSuffix(int subject_length) {
2363 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
2364 }
2365 static inline ReplacementPart ReplacementString() {
2366 return ReplacementPart(REPLACEMENT_STRING, 0);
2367 }
2368 static inline ReplacementPart ReplacementSubString(int from, int to) {
2369 ASSERT(from >= 0);
2370 ASSERT(to > from);
2371 return ReplacementPart(-from, to);
2372 }
2373
2374 // If tag <= 0 then it is the negation of a start index of a substring of
2375 // the replacement pattern, otherwise it's a value from PartType.
2376 ReplacementPart(int tag, int data)
2377 : tag(tag), data(data) {
2378 // Must be non-positive or a PartType value.
2379 ASSERT(tag < NUMBER_OF_PART_TYPES);
2380 }
2381 // Either a value of PartType or a non-positive number that is
2382 // the negation of an index into the replacement string.
2383 int tag;
2384 // The data value's interpretation depends on the value of tag:
2385 // tag == SUBJECT_PREFIX ||
2386 // tag == SUBJECT_SUFFIX: data is unused.
2387 // tag == SUBJECT_CAPTURE: data is the number of the capture.
2388 // tag == REPLACEMENT_SUBSTRING ||
2389 // tag == REPLACEMENT_STRING: data is index into array of substrings
2390 // of the replacement string.
2391 // tag <= 0: Temporary representation of the substring of the replacement
2392 // string ranging over -tag .. data.
2393 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
2394 // substring objects.
2395 int data;
2396 };
2397
2398 template<typename Char>
2399 static void ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
2400 Vector<Char> characters,
2401 int capture_count,
2402 int subject_length) {
2403 int length = characters.length();
2404 int last = 0;
2405 for (int i = 0; i < length; i++) {
2406 Char c = characters[i];
2407 if (c == '$') {
2408 int next_index = i + 1;
2409 if (next_index == length) { // No next character!
2410 break;
2411 }
2412 Char c2 = characters[next_index];
2413 switch (c2) {
2414 case '$':
2415 if (i > last) {
2416 // There is a substring before. Include the first "$".
2417 parts->Add(ReplacementPart::ReplacementSubString(last, next_index));
2418 last = next_index + 1; // Continue after the second "$".
2419 } else {
2420 // Let the next substring start with the second "$".
2421 last = next_index;
2422 }
2423 i = next_index;
2424 break;
2425 case '`':
2426 if (i > last) {
2427 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2428 }
2429 parts->Add(ReplacementPart::SubjectPrefix());
2430 i = next_index;
2431 last = i + 1;
2432 break;
2433 case '\'':
2434 if (i > last) {
2435 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2436 }
2437 parts->Add(ReplacementPart::SubjectSuffix(subject_length));
2438 i = next_index;
2439 last = i + 1;
2440 break;
2441 case '&':
2442 if (i > last) {
2443 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2444 }
2445 parts->Add(ReplacementPart::SubjectMatch());
2446 i = next_index;
2447 last = i + 1;
2448 break;
2449 case '0':
2450 case '1':
2451 case '2':
2452 case '3':
2453 case '4':
2454 case '5':
2455 case '6':
2456 case '7':
2457 case '8':
2458 case '9': {
2459 int capture_ref = c2 - '0';
2460 if (capture_ref > capture_count) {
2461 i = next_index;
2462 continue;
2463 }
2464 int second_digit_index = next_index + 1;
2465 if (second_digit_index < length) {
2466 // Peek ahead to see if we have two digits.
2467 Char c3 = characters[second_digit_index];
2468 if ('0' <= c3 && c3 <= '9') { // Double digits.
2469 int double_digit_ref = capture_ref * 10 + c3 - '0';
2470 if (double_digit_ref <= capture_count) {
2471 next_index = second_digit_index;
2472 capture_ref = double_digit_ref;
2473 }
2474 }
2475 }
2476 if (capture_ref > 0) {
2477 if (i > last) {
2478 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2479 }
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002480 ASSERT(capture_ref <= capture_count);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002481 parts->Add(ReplacementPart::SubjectCapture(capture_ref));
2482 last = next_index + 1;
2483 }
2484 i = next_index;
2485 break;
2486 }
2487 default:
2488 i = next_index;
2489 break;
2490 }
2491 }
2492 }
2493 if (length > last) {
2494 if (last == 0) {
2495 parts->Add(ReplacementPart::ReplacementString());
2496 } else {
2497 parts->Add(ReplacementPart::ReplacementSubString(last, length));
2498 }
2499 }
2500 }
2501
2502 ZoneList<ReplacementPart> parts_;
2503 ZoneList<Handle<String> > replacement_substrings_;
2504};
2505
2506
2507void CompiledReplacement::Compile(Handle<String> replacement,
2508 int capture_count,
2509 int subject_length) {
2510 ASSERT(replacement->IsFlat());
ager@chromium.org5ec48922009-05-05 07:25:34 +00002511 if (replacement->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002512 AssertNoAllocation no_alloc;
2513 ParseReplacementPattern(&parts_,
2514 replacement->ToAsciiVector(),
2515 capture_count,
2516 subject_length);
2517 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00002518 ASSERT(replacement->IsTwoByteRepresentation());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002519 AssertNoAllocation no_alloc;
2520
2521 ParseReplacementPattern(&parts_,
2522 replacement->ToUC16Vector(),
2523 capture_count,
2524 subject_length);
2525 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002526 Isolate* isolate = replacement->GetIsolate();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002527 // Find substrings of replacement string and create them as String objects.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002528 int substring_index = 0;
2529 for (int i = 0, n = parts_.length(); i < n; i++) {
2530 int tag = parts_[i].tag;
2531 if (tag <= 0) { // A replacement string slice.
2532 int from = -tag;
2533 int to = parts_[i].data;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002534 replacement_substrings_.Add(
2535 isolate->factory()->NewSubString(replacement, from, to));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002536 parts_[i].tag = REPLACEMENT_SUBSTRING;
2537 parts_[i].data = substring_index;
2538 substring_index++;
2539 } else if (tag == REPLACEMENT_STRING) {
2540 replacement_substrings_.Add(replacement);
2541 parts_[i].data = substring_index;
2542 substring_index++;
2543 }
2544 }
2545}
2546
2547
2548void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
2549 int match_from,
2550 int match_to,
2551 Handle<JSArray> last_match_info) {
2552 for (int i = 0, n = parts_.length(); i < n; i++) {
2553 ReplacementPart part = parts_[i];
2554 switch (part.tag) {
2555 case SUBJECT_PREFIX:
2556 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
2557 break;
2558 case SUBJECT_SUFFIX: {
2559 int subject_length = part.data;
2560 if (match_to < subject_length) {
2561 builder->AddSubjectSlice(match_to, subject_length);
2562 }
2563 break;
2564 }
2565 case SUBJECT_CAPTURE: {
2566 int capture = part.data;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002567 FixedArray* match_info = FixedArray::cast(last_match_info->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002568 int from = RegExpImpl::GetCapture(match_info, capture * 2);
2569 int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1);
2570 if (from >= 0 && to > from) {
2571 builder->AddSubjectSlice(from, to);
2572 }
2573 break;
2574 }
2575 case REPLACEMENT_SUBSTRING:
2576 case REPLACEMENT_STRING:
2577 builder->AddString(replacement_substrings_[part.data]);
2578 break;
2579 default:
2580 UNREACHABLE();
2581 }
2582 }
2583}
2584
2585
2586
lrn@chromium.org303ada72010-10-27 09:33:13 +00002587MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002588 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002589 String* subject,
2590 JSRegExp* regexp,
2591 String* replacement,
2592 JSArray* last_match_info) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002593 ASSERT(subject->IsFlat());
2594 ASSERT(replacement->IsFlat());
2595
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002596 HandleScope handles(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002597
2598 int length = subject->length();
2599 Handle<String> subject_handle(subject);
2600 Handle<JSRegExp> regexp_handle(regexp);
2601 Handle<String> replacement_handle(replacement);
2602 Handle<JSArray> last_match_info_handle(last_match_info);
2603 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2604 subject_handle,
2605 0,
2606 last_match_info_handle);
2607 if (match.is_null()) {
2608 return Failure::Exception();
2609 }
2610 if (match->IsNull()) {
2611 return *subject_handle;
2612 }
2613
2614 int capture_count = regexp_handle->CaptureCount();
2615
2616 // CompiledReplacement uses zone allocation.
danno@chromium.org40cb8782011-05-25 07:58:50 +00002617 CompilationZoneScope zone(isolate, DELETE_ON_EXIT);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002618 CompiledReplacement compiled_replacement;
2619 compiled_replacement.Compile(replacement_handle,
2620 capture_count,
2621 length);
2622
2623 bool is_global = regexp_handle->GetFlags().is_global();
2624
2625 // Guessing the number of parts that the final result string is built
2626 // from. Global regexps can match any number of times, so we guess
2627 // conservatively.
2628 int expected_parts =
2629 (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002630 ReplacementStringBuilder builder(isolate->heap(),
2631 subject_handle,
2632 expected_parts);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002633
2634 // Index of end of last match.
2635 int prev = 0;
2636
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002637 // Number of parts added by compiled replacement plus preceeding
2638 // string and possibly suffix after last match. It is possible for
2639 // all components to use two elements when encoded as two smis.
2640 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002641 bool matched = true;
2642 do {
2643 ASSERT(last_match_info_handle->HasFastElements());
2644 // Increase the capacity of the builder before entering local handle-scope,
2645 // so its internal buffer can safely allocate a new handle if it grows.
2646 builder.EnsureCapacity(parts_added_per_loop);
2647
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002648 HandleScope loop_scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002649 int start, end;
2650 {
2651 AssertNoAllocation match_info_array_is_not_in_a_handle;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002652 FixedArray* match_info_array =
2653 FixedArray::cast(last_match_info_handle->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002654
2655 ASSERT_EQ(capture_count * 2 + 2,
2656 RegExpImpl::GetLastCaptureCount(match_info_array));
2657 start = RegExpImpl::GetCapture(match_info_array, 0);
2658 end = RegExpImpl::GetCapture(match_info_array, 1);
2659 }
2660
2661 if (prev < start) {
2662 builder.AddSubjectSlice(prev, start);
2663 }
2664 compiled_replacement.Apply(&builder,
2665 start,
2666 end,
2667 last_match_info_handle);
2668 prev = end;
2669
2670 // Only continue checking for global regexps.
2671 if (!is_global) break;
2672
2673 // Continue from where the match ended, unless it was an empty match.
2674 int next = end;
2675 if (start == end) {
2676 next = end + 1;
2677 if (next > length) break;
2678 }
2679
2680 match = RegExpImpl::Exec(regexp_handle,
2681 subject_handle,
2682 next,
2683 last_match_info_handle);
2684 if (match.is_null()) {
2685 return Failure::Exception();
2686 }
2687 matched = !match->IsNull();
2688 } while (matched);
2689
2690 if (prev < length) {
2691 builder.AddSubjectSlice(prev, length);
2692 }
2693
2694 return *(builder.ToString());
2695}
2696
2697
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002698template <typename ResultSeqString>
lrn@chromium.org303ada72010-10-27 09:33:13 +00002699MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002700 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002701 String* subject,
2702 JSRegExp* regexp,
2703 JSArray* last_match_info) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002704 ASSERT(subject->IsFlat());
2705
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002706 HandleScope handles(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002707
2708 Handle<String> subject_handle(subject);
2709 Handle<JSRegExp> regexp_handle(regexp);
2710 Handle<JSArray> last_match_info_handle(last_match_info);
2711 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2712 subject_handle,
2713 0,
2714 last_match_info_handle);
2715 if (match.is_null()) return Failure::Exception();
2716 if (match->IsNull()) return *subject_handle;
2717
2718 ASSERT(last_match_info_handle->HasFastElements());
2719
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002720 int start, end;
2721 {
2722 AssertNoAllocation match_info_array_is_not_in_a_handle;
2723 FixedArray* match_info_array =
2724 FixedArray::cast(last_match_info_handle->elements());
2725
2726 start = RegExpImpl::GetCapture(match_info_array, 0);
2727 end = RegExpImpl::GetCapture(match_info_array, 1);
2728 }
2729
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00002730 int length = subject_handle->length();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002731 int new_length = length - (end - start);
2732 if (new_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002733 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002734 }
2735 Handle<ResultSeqString> answer;
2736 if (ResultSeqString::kHasAsciiEncoding) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002737 answer = Handle<ResultSeqString>::cast(
2738 isolate->factory()->NewRawAsciiString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002739 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002740 answer = Handle<ResultSeqString>::cast(
2741 isolate->factory()->NewRawTwoByteString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002742 }
2743
2744 // If the regexp isn't global, only match once.
2745 if (!regexp_handle->GetFlags().is_global()) {
2746 if (start > 0) {
2747 String::WriteToFlat(*subject_handle,
2748 answer->GetChars(),
2749 0,
2750 start);
2751 }
2752 if (end < length) {
2753 String::WriteToFlat(*subject_handle,
2754 answer->GetChars() + start,
2755 end,
2756 length);
2757 }
2758 return *answer;
2759 }
2760
2761 int prev = 0; // Index of end of last match.
2762 int next = 0; // Start of next search (prev unless last match was empty).
2763 int position = 0;
2764
2765 do {
2766 if (prev < start) {
2767 // Add substring subject[prev;start] to answer string.
2768 String::WriteToFlat(*subject_handle,
2769 answer->GetChars() + position,
2770 prev,
2771 start);
2772 position += start - prev;
2773 }
2774 prev = end;
2775 next = end;
2776 // Continue from where the match ended, unless it was an empty match.
2777 if (start == end) {
2778 next++;
2779 if (next > length) break;
2780 }
2781 match = RegExpImpl::Exec(regexp_handle,
2782 subject_handle,
2783 next,
2784 last_match_info_handle);
2785 if (match.is_null()) return Failure::Exception();
2786 if (match->IsNull()) break;
2787
2788 ASSERT(last_match_info_handle->HasFastElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002789 HandleScope loop_scope(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002790 {
2791 AssertNoAllocation match_info_array_is_not_in_a_handle;
2792 FixedArray* match_info_array =
2793 FixedArray::cast(last_match_info_handle->elements());
2794 start = RegExpImpl::GetCapture(match_info_array, 0);
2795 end = RegExpImpl::GetCapture(match_info_array, 1);
2796 }
2797 } while (true);
2798
2799 if (prev < length) {
2800 // Add substring subject[prev;length] to answer string.
2801 String::WriteToFlat(*subject_handle,
2802 answer->GetChars() + position,
2803 prev,
2804 length);
2805 position += length - prev;
2806 }
2807
2808 if (position == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002809 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002810 }
2811
2812 // Shorten string and fill
2813 int string_size = ResultSeqString::SizeFor(position);
2814 int allocated_string_size = ResultSeqString::SizeFor(new_length);
2815 int delta = allocated_string_size - string_size;
2816
2817 answer->set_length(position);
2818 if (delta == 0) return *answer;
2819
2820 Address end_of_string = answer->address() + string_size;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002821 isolate->heap()->CreateFillerObjectAt(end_of_string, delta);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002822
2823 return *answer;
2824}
2825
2826
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002827RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceRegExpWithString) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002828 ASSERT(args.length() == 4);
2829
2830 CONVERT_CHECKED(String, subject, args[0]);
2831 if (!subject->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002832 Object* flat_subject;
2833 { MaybeObject* maybe_flat_subject = subject->TryFlatten();
2834 if (!maybe_flat_subject->ToObject(&flat_subject)) {
2835 return maybe_flat_subject;
2836 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002837 }
2838 subject = String::cast(flat_subject);
2839 }
2840
2841 CONVERT_CHECKED(String, replacement, args[2]);
2842 if (!replacement->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002843 Object* flat_replacement;
2844 { MaybeObject* maybe_flat_replacement = replacement->TryFlatten();
2845 if (!maybe_flat_replacement->ToObject(&flat_replacement)) {
2846 return maybe_flat_replacement;
2847 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002848 }
2849 replacement = String::cast(flat_replacement);
2850 }
2851
2852 CONVERT_CHECKED(JSRegExp, regexp, args[1]);
2853 CONVERT_CHECKED(JSArray, last_match_info, args[3]);
2854
2855 ASSERT(last_match_info->HasFastElements());
2856
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002857 if (replacement->length() == 0) {
2858 if (subject->HasOnlyAsciiChars()) {
2859 return StringReplaceRegExpWithEmptyString<SeqAsciiString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002860 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002861 } else {
2862 return StringReplaceRegExpWithEmptyString<SeqTwoByteString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002863 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002864 }
2865 }
2866
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002867 return StringReplaceRegExpWithString(isolate,
2868 subject,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002869 regexp,
2870 replacement,
2871 last_match_info);
2872}
2873
2874
ager@chromium.org7c537e22008-10-16 08:43:32 +00002875// Perform string match of pattern on subject, starting at start index.
2876// Caller must ensure that 0 <= start_index <= sub->length(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002877// and should check that pat->length() + start_index <= sub->length().
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002878int Runtime::StringMatch(Isolate* isolate,
2879 Handle<String> sub,
ager@chromium.org7c537e22008-10-16 08:43:32 +00002880 Handle<String> pat,
2881 int start_index) {
2882 ASSERT(0 <= start_index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002883 ASSERT(start_index <= sub->length());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002884
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00002885 int pattern_length = pat->length();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002886 if (pattern_length == 0) return start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002887
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002888 int subject_length = sub->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00002889 if (start_index + pattern_length > subject_length) return -1;
2890
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002891 if (!sub->IsFlat()) FlattenString(sub);
2892 if (!pat->IsFlat()) FlattenString(pat);
ager@chromium.org236ad962008-09-25 09:45:57 +00002893
ager@chromium.org7c537e22008-10-16 08:43:32 +00002894 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002895 // Extract flattened substrings of cons strings before determining asciiness.
2896 String* seq_sub = *sub;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002897 if (seq_sub->IsConsString()) seq_sub = ConsString::cast(seq_sub)->first();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002898 String* seq_pat = *pat;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002899 if (seq_pat->IsConsString()) seq_pat = ConsString::cast(seq_pat)->first();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002900
ager@chromium.org7c537e22008-10-16 08:43:32 +00002901 // dispatch on type of strings
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002902 if (seq_pat->IsAsciiRepresentation()) {
2903 Vector<const char> pat_vector = seq_pat->ToAsciiVector();
2904 if (seq_sub->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002905 return SearchString(isolate,
2906 seq_sub->ToAsciiVector(),
2907 pat_vector,
2908 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00002909 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002910 return SearchString(isolate,
2911 seq_sub->ToUC16Vector(),
2912 pat_vector,
2913 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00002914 }
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002915 Vector<const uc16> pat_vector = seq_pat->ToUC16Vector();
2916 if (seq_sub->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002917 return SearchString(isolate,
2918 seq_sub->ToAsciiVector(),
2919 pat_vector,
2920 start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002921 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002922 return SearchString(isolate,
2923 seq_sub->ToUC16Vector(),
2924 pat_vector,
2925 start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002926}
2927
2928
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002929RUNTIME_FUNCTION(MaybeObject*, Runtime_StringIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002930 HandleScope scope(isolate); // create a new handle scope
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002931 ASSERT(args.length() == 3);
2932
ager@chromium.org7c537e22008-10-16 08:43:32 +00002933 CONVERT_ARG_CHECKED(String, sub, 0);
2934 CONVERT_ARG_CHECKED(String, pat, 1);
2935
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002936 Object* index = args[2];
2937 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002938 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002939
ager@chromium.org870a0b62008-11-04 11:43:05 +00002940 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002941 int position =
2942 Runtime::StringMatch(isolate, sub, pat, start_index);
ager@chromium.org7c537e22008-10-16 08:43:32 +00002943 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002944}
2945
2946
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002947template <typename schar, typename pchar>
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002948static int StringMatchBackwards(Vector<const schar> subject,
2949 Vector<const pchar> pattern,
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002950 int idx) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002951 int pattern_length = pattern.length();
2952 ASSERT(pattern_length >= 1);
2953 ASSERT(idx + pattern_length <= subject.length());
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002954
2955 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002956 for (int i = 0; i < pattern_length; i++) {
2957 uc16 c = pattern[i];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002958 if (c > String::kMaxAsciiCharCode) {
2959 return -1;
2960 }
2961 }
2962 }
2963
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002964 pchar pattern_first_char = pattern[0];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002965 for (int i = idx; i >= 0; i--) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002966 if (subject[i] != pattern_first_char) continue;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002967 int j = 1;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002968 while (j < pattern_length) {
2969 if (pattern[j] != subject[i+j]) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002970 break;
2971 }
2972 j++;
2973 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002974 if (j == pattern_length) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002975 return i;
2976 }
2977 }
2978 return -1;
2979}
2980
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002981RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLastIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002982 HandleScope scope(isolate); // create a new handle scope
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002983 ASSERT(args.length() == 3);
2984
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002985 CONVERT_ARG_CHECKED(String, sub, 0);
2986 CONVERT_ARG_CHECKED(String, pat, 1);
2987
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002988 Object* index = args[2];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002989 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002990 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002991
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002992 uint32_t pat_length = pat->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002993 uint32_t sub_length = sub->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002994
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002995 if (start_index + pat_length > sub_length) {
2996 start_index = sub_length - pat_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +00002997 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002998
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002999 if (pat_length == 0) {
3000 return Smi::FromInt(start_index);
3001 }
3002
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003003 if (!sub->IsFlat()) FlattenString(sub);
3004 if (!pat->IsFlat()) FlattenString(pat);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003005
3006 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
3007
3008 int position = -1;
3009
3010 if (pat->IsAsciiRepresentation()) {
3011 Vector<const char> pat_vector = pat->ToAsciiVector();
3012 if (sub->IsAsciiRepresentation()) {
3013 position = StringMatchBackwards(sub->ToAsciiVector(),
3014 pat_vector,
3015 start_index);
3016 } else {
3017 position = StringMatchBackwards(sub->ToUC16Vector(),
3018 pat_vector,
3019 start_index);
3020 }
3021 } else {
3022 Vector<const uc16> pat_vector = pat->ToUC16Vector();
3023 if (sub->IsAsciiRepresentation()) {
3024 position = StringMatchBackwards(sub->ToAsciiVector(),
3025 pat_vector,
3026 start_index);
3027 } else {
3028 position = StringMatchBackwards(sub->ToUC16Vector(),
3029 pat_vector,
3030 start_index);
3031 }
3032 }
3033
3034 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003035}
3036
3037
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003038RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLocaleCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003039 NoHandleAllocation ha;
3040 ASSERT(args.length() == 2);
3041
3042 CONVERT_CHECKED(String, str1, args[0]);
3043 CONVERT_CHECKED(String, str2, args[1]);
3044
3045 if (str1 == str2) return Smi::FromInt(0); // Equal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003046 int str1_length = str1->length();
3047 int str2_length = str2->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003048
3049 // Decide trivial cases without flattening.
3050 if (str1_length == 0) {
3051 if (str2_length == 0) return Smi::FromInt(0); // Equal.
3052 return Smi::FromInt(-str2_length);
3053 } else {
3054 if (str2_length == 0) return Smi::FromInt(str1_length);
3055 }
3056
3057 int end = str1_length < str2_length ? str1_length : str2_length;
3058
3059 // No need to flatten if we are going to find the answer on the first
3060 // character. At this point we know there is at least one character
3061 // in each string, due to the trivial case handling above.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003062 int d = str1->Get(0) - str2->Get(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003063 if (d != 0) return Smi::FromInt(d);
3064
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003065 str1->TryFlatten();
3066 str2->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003067
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003068 StringInputBuffer& buf1 =
3069 *isolate->runtime_state()->string_locale_compare_buf1();
3070 StringInputBuffer& buf2 =
3071 *isolate->runtime_state()->string_locale_compare_buf2();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003072
3073 buf1.Reset(str1);
3074 buf2.Reset(str2);
3075
3076 for (int i = 0; i < end; i++) {
3077 uint16_t char1 = buf1.GetNext();
3078 uint16_t char2 = buf2.GetNext();
3079 if (char1 != char2) return Smi::FromInt(char1 - char2);
3080 }
3081
3082 return Smi::FromInt(str1_length - str2_length);
3083}
3084
3085
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003086RUNTIME_FUNCTION(MaybeObject*, Runtime_SubString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003087 NoHandleAllocation ha;
3088 ASSERT(args.length() == 3);
3089
3090 CONVERT_CHECKED(String, value, args[0]);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003091 Object* from = args[1];
3092 Object* to = args[2];
3093 int start, end;
3094 // We have a fast integer-only case here to avoid a conversion to double in
3095 // the common case where from and to are Smis.
3096 if (from->IsSmi() && to->IsSmi()) {
3097 start = Smi::cast(from)->value();
3098 end = Smi::cast(to)->value();
3099 } else {
3100 CONVERT_DOUBLE_CHECKED(from_number, from);
3101 CONVERT_DOUBLE_CHECKED(to_number, to);
3102 start = FastD2I(from_number);
3103 end = FastD2I(to_number);
3104 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003105 RUNTIME_ASSERT(end >= start);
3106 RUNTIME_ASSERT(start >= 0);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003107 RUNTIME_ASSERT(end <= value->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003108 isolate->counters()->sub_string_runtime()->Increment();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003109 return value->SubString(start, end);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003110}
3111
3112
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003113RUNTIME_FUNCTION(MaybeObject*, Runtime_StringMatch) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003114 ASSERT_EQ(3, args.length());
3115
3116 CONVERT_ARG_CHECKED(String, subject, 0);
3117 CONVERT_ARG_CHECKED(JSRegExp, regexp, 1);
3118 CONVERT_ARG_CHECKED(JSArray, regexp_info, 2);
3119 HandleScope handles;
3120
3121 Handle<Object> match = RegExpImpl::Exec(regexp, subject, 0, regexp_info);
3122
3123 if (match.is_null()) {
3124 return Failure::Exception();
3125 }
3126 if (match->IsNull()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003127 return isolate->heap()->null_value();
ager@chromium.org41826e72009-03-30 13:30:57 +00003128 }
3129 int length = subject->length();
3130
danno@chromium.org40cb8782011-05-25 07:58:50 +00003131 CompilationZoneScope zone_space(isolate, DELETE_ON_EXIT);
ager@chromium.org41826e72009-03-30 13:30:57 +00003132 ZoneList<int> offsets(8);
3133 do {
3134 int start;
3135 int end;
3136 {
3137 AssertNoAllocation no_alloc;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003138 FixedArray* elements = FixedArray::cast(regexp_info->elements());
ager@chromium.org41826e72009-03-30 13:30:57 +00003139 start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value();
3140 end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value();
3141 }
3142 offsets.Add(start);
3143 offsets.Add(end);
3144 int index = start < end ? end : end + 1;
3145 if (index > length) break;
3146 match = RegExpImpl::Exec(regexp, subject, index, regexp_info);
3147 if (match.is_null()) {
3148 return Failure::Exception();
3149 }
3150 } while (!match->IsNull());
3151 int matches = offsets.length() / 2;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003152 Handle<FixedArray> elements = isolate->factory()->NewFixedArray(matches);
ager@chromium.org41826e72009-03-30 13:30:57 +00003153 for (int i = 0; i < matches ; i++) {
3154 int from = offsets.at(i * 2);
3155 int to = offsets.at(i * 2 + 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003156 Handle<String> match = isolate->factory()->NewSubString(subject, from, to);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003157 elements->set(i, *match);
ager@chromium.org41826e72009-03-30 13:30:57 +00003158 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003159 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.org41826e72009-03-30 13:30:57 +00003160 result->set_length(Smi::FromInt(matches));
3161 return *result;
3162}
3163
3164
lrn@chromium.org25156de2010-04-06 13:10:27 +00003165// Two smis before and after the match, for very long strings.
3166const int kMaxBuilderEntriesPerRegExpMatch = 5;
3167
3168
3169static void SetLastMatchInfoNoCaptures(Handle<String> subject,
3170 Handle<JSArray> last_match_info,
3171 int match_start,
3172 int match_end) {
3173 // Fill last_match_info with a single capture.
3174 last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead);
3175 AssertNoAllocation no_gc;
3176 FixedArray* elements = FixedArray::cast(last_match_info->elements());
3177 RegExpImpl::SetLastCaptureCount(elements, 2);
3178 RegExpImpl::SetLastInput(elements, *subject);
3179 RegExpImpl::SetLastSubject(elements, *subject);
3180 RegExpImpl::SetCapture(elements, 0, match_start);
3181 RegExpImpl::SetCapture(elements, 1, match_end);
3182}
3183
3184
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003185template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003186static bool SearchStringMultiple(Isolate* isolate,
3187 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003188 Vector<const PatternChar> pattern,
3189 String* pattern_string,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003190 FixedArrayBuilder* builder,
3191 int* match_pos) {
3192 int pos = *match_pos;
3193 int subject_length = subject.length();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003194 int pattern_length = pattern.length();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003195 int max_search_start = subject_length - pattern_length;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003196 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003197 while (pos <= max_search_start) {
3198 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
3199 *match_pos = pos;
3200 return false;
3201 }
3202 // Position of end of previous match.
3203 int match_end = pos + pattern_length;
3204 int new_pos = search.Search(subject, match_end);
3205 if (new_pos >= 0) {
3206 // A match.
3207 if (new_pos > match_end) {
3208 ReplacementStringBuilder::AddSubjectSlice(builder,
3209 match_end,
3210 new_pos);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003211 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003212 pos = new_pos;
3213 builder->Add(pattern_string);
3214 } else {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003215 break;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003216 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003217 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003218
lrn@chromium.org25156de2010-04-06 13:10:27 +00003219 if (pos < max_search_start) {
3220 ReplacementStringBuilder::AddSubjectSlice(builder,
3221 pos + pattern_length,
3222 subject_length);
3223 }
3224 *match_pos = pos;
3225 return true;
3226}
3227
3228
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003229static bool SearchStringMultiple(Isolate* isolate,
3230 Handle<String> subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003231 Handle<String> pattern,
3232 Handle<JSArray> last_match_info,
3233 FixedArrayBuilder* builder) {
3234 ASSERT(subject->IsFlat());
3235 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003236
3237 // Treating as if a previous match was before first character.
3238 int match_pos = -pattern->length();
3239
3240 for (;;) { // Break when search complete.
3241 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3242 AssertNoAllocation no_gc;
3243 if (subject->IsAsciiRepresentation()) {
3244 Vector<const char> subject_vector = subject->ToAsciiVector();
3245 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003246 if (SearchStringMultiple(isolate,
3247 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003248 pattern->ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003249 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003250 builder,
3251 &match_pos)) break;
3252 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003253 if (SearchStringMultiple(isolate,
3254 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003255 pattern->ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003256 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003257 builder,
3258 &match_pos)) break;
3259 }
3260 } else {
3261 Vector<const uc16> subject_vector = subject->ToUC16Vector();
3262 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003263 if (SearchStringMultiple(isolate,
3264 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003265 pattern->ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003266 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003267 builder,
3268 &match_pos)) break;
3269 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003270 if (SearchStringMultiple(isolate,
3271 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003272 pattern->ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003273 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003274 builder,
3275 &match_pos)) break;
3276 }
3277 }
3278 }
3279
3280 if (match_pos >= 0) {
3281 SetLastMatchInfoNoCaptures(subject,
3282 last_match_info,
3283 match_pos,
3284 match_pos + pattern->length());
3285 return true;
3286 }
3287 return false; // No matches at all.
3288}
3289
3290
3291static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003292 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003293 Handle<String> subject,
3294 Handle<JSRegExp> regexp,
3295 Handle<JSArray> last_match_array,
3296 FixedArrayBuilder* builder) {
3297 ASSERT(subject->IsFlat());
3298 int match_start = -1;
3299 int match_end = 0;
3300 int pos = 0;
3301 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3302 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3303
3304 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003305 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003306 int subject_length = subject->length();
3307
3308 for (;;) { // Break on failure, return on exception.
3309 RegExpImpl::IrregexpResult result =
3310 RegExpImpl::IrregexpExecOnce(regexp,
3311 subject,
3312 pos,
3313 register_vector);
3314 if (result == RegExpImpl::RE_SUCCESS) {
3315 match_start = register_vector[0];
3316 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3317 if (match_end < match_start) {
3318 ReplacementStringBuilder::AddSubjectSlice(builder,
3319 match_end,
3320 match_start);
3321 }
3322 match_end = register_vector[1];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003323 HandleScope loop_scope(isolate);
3324 builder->Add(*isolate->factory()->NewSubString(subject,
3325 match_start,
3326 match_end));
lrn@chromium.org25156de2010-04-06 13:10:27 +00003327 if (match_start != match_end) {
3328 pos = match_end;
3329 } else {
3330 pos = match_end + 1;
3331 if (pos > subject_length) break;
3332 }
3333 } else if (result == RegExpImpl::RE_FAILURE) {
3334 break;
3335 } else {
3336 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3337 return result;
3338 }
3339 }
3340
3341 if (match_start >= 0) {
3342 if (match_end < subject_length) {
3343 ReplacementStringBuilder::AddSubjectSlice(builder,
3344 match_end,
3345 subject_length);
3346 }
3347 SetLastMatchInfoNoCaptures(subject,
3348 last_match_array,
3349 match_start,
3350 match_end);
3351 return RegExpImpl::RE_SUCCESS;
3352 } else {
3353 return RegExpImpl::RE_FAILURE; // No matches at all.
3354 }
3355}
3356
3357
3358static RegExpImpl::IrregexpResult SearchRegExpMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003359 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003360 Handle<String> subject,
3361 Handle<JSRegExp> regexp,
3362 Handle<JSArray> last_match_array,
3363 FixedArrayBuilder* builder) {
3364
3365 ASSERT(subject->IsFlat());
3366 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3367 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3368
3369 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003370 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003371
3372 RegExpImpl::IrregexpResult result =
3373 RegExpImpl::IrregexpExecOnce(regexp,
3374 subject,
3375 0,
3376 register_vector);
3377
3378 int capture_count = regexp->CaptureCount();
3379 int subject_length = subject->length();
3380
3381 // Position to search from.
3382 int pos = 0;
3383 // End of previous match. Differs from pos if match was empty.
3384 int match_end = 0;
3385 if (result == RegExpImpl::RE_SUCCESS) {
3386 // Need to keep a copy of the previous match for creating last_match_info
3387 // at the end, so we have two vectors that we swap between.
3388 OffsetsVector registers2(required_registers);
3389 Vector<int> prev_register_vector(registers2.vector(), registers2.length());
3390
3391 do {
3392 int match_start = register_vector[0];
3393 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3394 if (match_end < match_start) {
3395 ReplacementStringBuilder::AddSubjectSlice(builder,
3396 match_end,
3397 match_start);
3398 }
3399 match_end = register_vector[1];
3400
3401 {
3402 // Avoid accumulating new handles inside loop.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003403 HandleScope temp_scope(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003404 // Arguments array to replace function is match, captures, index and
3405 // subject, i.e., 3 + capture count in total.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003406 Handle<FixedArray> elements =
3407 isolate->factory()->NewFixedArray(3 + capture_count);
3408 Handle<String> match = isolate->factory()->NewSubString(subject,
3409 match_start,
3410 match_end);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003411 elements->set(0, *match);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003412 for (int i = 1; i <= capture_count; i++) {
3413 int start = register_vector[i * 2];
3414 if (start >= 0) {
3415 int end = register_vector[i * 2 + 1];
3416 ASSERT(start <= end);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003417 Handle<String> substring = isolate->factory()->NewSubString(subject,
3418 start,
3419 end);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003420 elements->set(i, *substring);
3421 } else {
3422 ASSERT(register_vector[i * 2 + 1] < 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003423 elements->set(i, isolate->heap()->undefined_value());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003424 }
3425 }
3426 elements->set(capture_count + 1, Smi::FromInt(match_start));
3427 elements->set(capture_count + 2, *subject);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003428 builder->Add(*isolate->factory()->NewJSArrayWithElements(elements));
lrn@chromium.org25156de2010-04-06 13:10:27 +00003429 }
3430 // Swap register vectors, so the last successful match is in
3431 // prev_register_vector.
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003432 Vector<int32_t> tmp = prev_register_vector;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003433 prev_register_vector = register_vector;
3434 register_vector = tmp;
3435
3436 if (match_end > match_start) {
3437 pos = match_end;
3438 } else {
3439 pos = match_end + 1;
3440 if (pos > subject_length) {
3441 break;
3442 }
3443 }
3444
3445 result = RegExpImpl::IrregexpExecOnce(regexp,
3446 subject,
3447 pos,
3448 register_vector);
3449 } while (result == RegExpImpl::RE_SUCCESS);
3450
3451 if (result != RegExpImpl::RE_EXCEPTION) {
3452 // Finished matching, with at least one match.
3453 if (match_end < subject_length) {
3454 ReplacementStringBuilder::AddSubjectSlice(builder,
3455 match_end,
3456 subject_length);
3457 }
3458
3459 int last_match_capture_count = (capture_count + 1) * 2;
3460 int last_match_array_size =
3461 last_match_capture_count + RegExpImpl::kLastMatchOverhead;
3462 last_match_array->EnsureSize(last_match_array_size);
3463 AssertNoAllocation no_gc;
3464 FixedArray* elements = FixedArray::cast(last_match_array->elements());
3465 RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count);
3466 RegExpImpl::SetLastSubject(elements, *subject);
3467 RegExpImpl::SetLastInput(elements, *subject);
3468 for (int i = 0; i < last_match_capture_count; i++) {
3469 RegExpImpl::SetCapture(elements, i, prev_register_vector[i]);
3470 }
3471 return RegExpImpl::RE_SUCCESS;
3472 }
3473 }
3474 // No matches at all, return failure or exception result directly.
3475 return result;
3476}
3477
3478
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003479RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExecMultiple) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003480 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003481 HandleScope handles(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003482
3483 CONVERT_ARG_CHECKED(String, subject, 1);
3484 if (!subject->IsFlat()) { FlattenString(subject); }
3485 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
3486 CONVERT_ARG_CHECKED(JSArray, last_match_info, 2);
3487 CONVERT_ARG_CHECKED(JSArray, result_array, 3);
3488
3489 ASSERT(last_match_info->HasFastElements());
3490 ASSERT(regexp->GetFlags().is_global());
3491 Handle<FixedArray> result_elements;
3492 if (result_array->HasFastElements()) {
3493 result_elements =
3494 Handle<FixedArray>(FixedArray::cast(result_array->elements()));
3495 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003496 result_elements = isolate->factory()->NewFixedArrayWithHoles(16);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003497 }
3498 FixedArrayBuilder builder(result_elements);
3499
3500 if (regexp->TypeTag() == JSRegExp::ATOM) {
3501 Handle<String> pattern(
3502 String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003503 ASSERT(pattern->IsFlat());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003504 if (SearchStringMultiple(isolate, subject, pattern,
3505 last_match_info, &builder)) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003506 return *builder.ToJSArray(result_array);
3507 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003508 return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003509 }
3510
3511 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
3512
3513 RegExpImpl::IrregexpResult result;
3514 if (regexp->CaptureCount() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003515 result = SearchRegExpNoCaptureMultiple(isolate,
3516 subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003517 regexp,
3518 last_match_info,
3519 &builder);
3520 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003521 result = SearchRegExpMultiple(isolate,
3522 subject,
3523 regexp,
3524 last_match_info,
3525 &builder);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003526 }
3527 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003528 if (result == RegExpImpl::RE_FAILURE) return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003529 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3530 return Failure::Exception();
3531}
3532
3533
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003534RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToRadixString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003535 NoHandleAllocation ha;
3536 ASSERT(args.length() == 2);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00003537 CONVERT_SMI_CHECKED(radix, args[1]);
3538 RUNTIME_ASSERT(2 <= radix && radix <= 36);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003539
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003540 // Fast case where the result is a one character string.
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00003541 if (args[0]->IsSmi()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003542 int value = Smi::cast(args[0])->value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003543 if (value >= 0 && value < radix) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003544 // Character array used for conversion.
3545 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003546 return isolate->heap()->
3547 LookupSingleCharacterStringFromCode(kCharTable[value]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003548 }
3549 }
3550
3551 // Slow case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003552 CONVERT_DOUBLE_CHECKED(value, args[0]);
3553 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003554 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003555 }
3556 if (isinf(value)) {
3557 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003558 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003559 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003560 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003561 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003562 char* str = DoubleToRadixCString(value, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003563 MaybeObject* result =
3564 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003565 DeleteArray(str);
3566 return result;
3567}
3568
3569
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003570RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToFixed) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003571 NoHandleAllocation ha;
3572 ASSERT(args.length() == 2);
3573
3574 CONVERT_DOUBLE_CHECKED(value, args[0]);
3575 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003576 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003577 }
3578 if (isinf(value)) {
3579 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003580 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003581 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003582 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003583 }
3584 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3585 int f = FastD2I(f_number);
3586 RUNTIME_ASSERT(f >= 0);
3587 char* str = DoubleToFixedCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003588 MaybeObject* res =
3589 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003590 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003591 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003592}
3593
3594
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003595RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToExponential) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003596 NoHandleAllocation ha;
3597 ASSERT(args.length() == 2);
3598
3599 CONVERT_DOUBLE_CHECKED(value, args[0]);
3600 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003601 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003602 }
3603 if (isinf(value)) {
3604 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003605 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003606 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003607 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003608 }
3609 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3610 int f = FastD2I(f_number);
3611 RUNTIME_ASSERT(f >= -1 && f <= 20);
3612 char* str = DoubleToExponentialCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003613 MaybeObject* res =
3614 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003615 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003616 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003617}
3618
3619
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003620RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToPrecision) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003621 NoHandleAllocation ha;
3622 ASSERT(args.length() == 2);
3623
3624 CONVERT_DOUBLE_CHECKED(value, args[0]);
3625 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003626 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003627 }
3628 if (isinf(value)) {
3629 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003630 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003631 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003632 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003633 }
3634 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3635 int f = FastD2I(f_number);
3636 RUNTIME_ASSERT(f >= 1 && f <= 21);
3637 char* str = DoubleToPrecisionCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003638 MaybeObject* res =
3639 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003640 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003641 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003642}
3643
3644
3645// Returns a single character string where first character equals
3646// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003647static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003648 if (index < static_cast<uint32_t>(string->length())) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003649 string->TryFlatten();
ager@chromium.org870a0b62008-11-04 11:43:05 +00003650 return LookupSingleCharacterStringFromCode(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003651 string->Get(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003652 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003653 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003654}
3655
3656
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003657MaybeObject* Runtime::GetElementOrCharAt(Isolate* isolate,
3658 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003659 uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003660 // Handle [] indexing on Strings
3661 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003662 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
3663 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003664 }
3665
3666 // Handle [] indexing on String objects
3667 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003668 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
3669 Handle<Object> result =
3670 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
3671 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003672 }
3673
3674 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003675 Handle<Object> prototype = GetPrototype(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003676 return prototype->GetElement(index);
3677 }
3678
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003679 return GetElement(object, index);
3680}
3681
3682
lrn@chromium.org303ada72010-10-27 09:33:13 +00003683MaybeObject* Runtime::GetElement(Handle<Object> object, uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003684 return object->GetElement(index);
3685}
3686
3687
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003688MaybeObject* Runtime::GetObjectProperty(Isolate* isolate,
3689 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003690 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003691 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003692
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003693 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003694 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003695 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003696 isolate->factory()->NewTypeError("non_object_property_load",
3697 HandleVector(args, 2));
3698 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003699 }
3700
3701 // Check if the given key is an array index.
3702 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003703 if (key->ToArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003704 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003705 }
3706
3707 // Convert the key to a string - possibly by calling back into JavaScript.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003708 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003709 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003710 name = Handle<String>::cast(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003711 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003712 bool has_pending_exception = false;
3713 Handle<Object> converted =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003714 Execution::ToString(key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003715 if (has_pending_exception) return Failure::Exception();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003716 name = Handle<String>::cast(converted);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003717 }
3718
ager@chromium.org32912102009-01-16 10:38:43 +00003719 // Check if the name is trivially convertible to an index and get
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003720 // the element if so.
3721 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003722 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003723 } else {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003724 return object->GetProperty(*name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003725 }
3726}
3727
3728
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003729RUNTIME_FUNCTION(MaybeObject*, Runtime_GetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003730 NoHandleAllocation ha;
3731 ASSERT(args.length() == 2);
3732
3733 Handle<Object> object = args.at<Object>(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003734 Handle<Object> key = args.at<Object>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003735
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003736 return Runtime::GetObjectProperty(isolate, object, key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003737}
3738
3739
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003740// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003741RUNTIME_FUNCTION(MaybeObject*, Runtime_KeyedGetProperty) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00003742 NoHandleAllocation ha;
3743 ASSERT(args.length() == 2);
3744
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003745 // Fast cases for getting named properties of the receiver JSObject
ager@chromium.org8bb60582008-12-11 12:02:20 +00003746 // itself.
3747 //
3748 // The global proxy objects has to be excluded since LocalLookup on
ager@chromium.org32912102009-01-16 10:38:43 +00003749 // the global proxy object can return a valid result even though the
ager@chromium.org8bb60582008-12-11 12:02:20 +00003750 // global proxy object never has properties. This is the case
3751 // because the global proxy object forwards everything to its hidden
3752 // prototype including local lookups.
3753 //
3754 // Additionally, we need to make sure that we do not cache results
3755 // for objects that require access checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003756 if (args[0]->IsJSObject() &&
3757 !args[0]->IsJSGlobalProxy() &&
ager@chromium.org8bb60582008-12-11 12:02:20 +00003758 !args[0]->IsAccessCheckNeeded() &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003759 args[1]->IsString()) {
3760 JSObject* receiver = JSObject::cast(args[0]);
3761 String* key = String::cast(args[1]);
3762 if (receiver->HasFastProperties()) {
3763 // Attempt to use lookup cache.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003764 Map* receiver_map = receiver->map();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003765 KeyedLookupCache* keyed_lookup_cache = isolate->keyed_lookup_cache();
3766 int offset = keyed_lookup_cache->Lookup(receiver_map, key);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00003767 if (offset != -1) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003768 Object* value = receiver->FastPropertyAt(offset);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003769 return value->IsTheHole() ? isolate->heap()->undefined_value() : value;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003770 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003771 // Lookup cache miss. Perform lookup and update the cache if appropriate.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003772 LookupResult result;
3773 receiver->LocalLookup(key, &result);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00003774 if (result.IsProperty() && result.type() == FIELD) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003775 int offset = result.GetFieldIndex();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003776 keyed_lookup_cache->Update(receiver_map, key, offset);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003777 return receiver->FastPropertyAt(offset);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003778 }
3779 } else {
3780 // Attempt dictionary lookup.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00003781 StringDictionary* dictionary = receiver->property_dictionary();
3782 int entry = dictionary->FindEntry(key);
3783 if ((entry != StringDictionary::kNotFound) &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003784 (dictionary->DetailsAt(entry).type() == NORMAL)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003785 Object* value = dictionary->ValueAt(entry);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003786 if (!receiver->IsGlobalObject()) return value;
3787 value = JSGlobalPropertyCell::cast(value)->value();
3788 if (!value->IsTheHole()) return value;
3789 // If value is the hole do the general lookup.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003790 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00003791 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003792 } else if (args[0]->IsString() && args[1]->IsSmi()) {
3793 // Fast case for string indexing using [] with a smi index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003794 HandleScope scope(isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003795 Handle<String> str = args.at<String>(0);
3796 int index = Smi::cast(args[1])->value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003797 if (index >= 0 && index < str->length()) {
3798 Handle<Object> result = GetCharAt(str, index);
3799 return *result;
3800 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00003801 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003802
3803 // Fall back to GetObjectProperty.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003804 return Runtime::GetObjectProperty(isolate,
3805 args.at<Object>(0),
ager@chromium.org7c537e22008-10-16 08:43:32 +00003806 args.at<Object>(1));
3807}
3808
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003809// Implements part of 8.12.9 DefineOwnProperty.
3810// There are 3 cases that lead here:
3811// Step 4b - define a new accessor property.
3812// Steps 9c & 12 - replace an existing data property with an accessor property.
3813// Step 12 - update an existing accessor property with an accessor or generic
3814// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003815RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineAccessorProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003816 ASSERT(args.length() == 5);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003817 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00003818 CONVERT_ARG_CHECKED(JSObject, obj, 0);
3819 CONVERT_CHECKED(String, name, args[1]);
3820 CONVERT_CHECKED(Smi, flag_setter, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003821 Object* fun = args[3];
3822 RUNTIME_ASSERT(fun->IsJSFunction() || fun->IsUndefined());
ager@chromium.org5c838252010-02-19 08:53:10 +00003823 CONVERT_CHECKED(Smi, flag_attr, args[4]);
3824 int unchecked = flag_attr->value();
3825 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3826 RUNTIME_ASSERT(!obj->IsNull());
3827 LookupResult result;
3828 obj->LocalLookupRealNamedProperty(name, &result);
3829
3830 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
3831 // If an existing property is either FIELD, NORMAL or CONSTANT_FUNCTION
3832 // delete it to avoid running into trouble in DefineAccessor, which
3833 // handles this incorrectly if the property is readonly (does nothing)
3834 if (result.IsProperty() &&
3835 (result.type() == FIELD || result.type() == NORMAL
3836 || result.type() == CONSTANT_FUNCTION)) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003837 Object* ok;
3838 { MaybeObject* maybe_ok =
3839 obj->DeleteProperty(name, JSObject::NORMAL_DELETION);
3840 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
3841 }
ager@chromium.org5c838252010-02-19 08:53:10 +00003842 }
3843 return obj->DefineAccessor(name, flag_setter->value() == 0, fun, attr);
3844}
3845
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003846// Implements part of 8.12.9 DefineOwnProperty.
3847// There are 3 cases that lead here:
3848// Step 4a - define a new data property.
3849// Steps 9b & 12 - replace an existing accessor property with a data property.
3850// Step 12 - update an existing data property with a data or generic
3851// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003852RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineDataProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003853 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003854 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00003855 CONVERT_ARG_CHECKED(JSObject, js_object, 0);
3856 CONVERT_ARG_CHECKED(String, name, 1);
3857 Handle<Object> obj_value = args.at<Object>(2);
3858
3859 CONVERT_CHECKED(Smi, flag, args[3]);
3860 int unchecked = flag->value();
3861 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3862
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003863 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
3864
3865 // Check if this is an element.
3866 uint32_t index;
3867 bool is_element = name->AsArrayIndex(&index);
3868
3869 // Special case for elements if any of the flags are true.
3870 // If elements are in fast case we always implicitly assume that:
3871 // DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
3872 if (((unchecked & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0) &&
3873 is_element) {
3874 // Normalize the elements to enable attributes on the property.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003875 if (js_object->IsJSGlobalProxy()) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003876 // We do not need to do access checks here since these has already
3877 // been performed by the call to GetOwnProperty.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003878 Handle<Object> proto(js_object->GetPrototype());
3879 // If proxy is detached, ignore the assignment. Alternatively,
3880 // we could throw an exception.
3881 if (proto->IsNull()) return *obj_value;
3882 js_object = Handle<JSObject>::cast(proto);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003883 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003884 NormalizeElements(js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003885 Handle<NumberDictionary> dictionary(js_object->element_dictionary());
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003886 // Make sure that we never go back to fast case.
3887 dictionary->set_requires_slow_elements();
3888 PropertyDetails details = PropertyDetails(attr, NORMAL);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003889 NumberDictionarySet(dictionary, index, obj_value, details);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003890 return *obj_value;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003891 }
3892
ager@chromium.org5c838252010-02-19 08:53:10 +00003893 LookupResult result;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003894 js_object->LookupRealNamedProperty(*name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00003895
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00003896 // To be compatible with safari we do not change the value on API objects
3897 // in defineProperty. Firefox disagrees here, and actually changes the value.
3898 if (result.IsProperty() &&
3899 (result.type() == CALLBACKS) &&
3900 result.GetCallbackObject()->IsAccessorInfo()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003901 return isolate->heap()->undefined_value();
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00003902 }
3903
ager@chromium.org5c838252010-02-19 08:53:10 +00003904 // Take special care when attributes are different and there is already
3905 // a property. For simplicity we normalize the property which enables us
3906 // to not worry about changing the instance_descriptor and creating a new
3907 // map. The current version of SetObjectProperty does not handle attributes
3908 // correctly in the case where a property is a field and is reset with
3909 // new attributes.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003910 if (result.IsProperty() &&
3911 (attr != result.GetAttributes() || result.type() == CALLBACKS)) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003912 // New attributes - normalize to avoid writing to instance descriptor
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003913 if (js_object->IsJSGlobalProxy()) {
3914 // Since the result is a property, the prototype will exist so
3915 // we don't have to check for null.
3916 js_object = Handle<JSObject>(JSObject::cast(js_object->GetPrototype()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003917 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003918 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00003919 // Use IgnoreAttributes version since a readonly property may be
3920 // overridden and SetProperty does not allow this.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003921 return js_object->SetLocalPropertyIgnoreAttributes(*name,
3922 *obj_value,
3923 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00003924 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003925
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003926 return Runtime::ForceSetObjectProperty(isolate,
3927 js_object,
3928 name,
3929 obj_value,
3930 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00003931}
3932
3933
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003934MaybeObject* Runtime::SetObjectProperty(Isolate* isolate,
3935 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003936 Handle<Object> key,
3937 Handle<Object> value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003938 PropertyAttributes attr,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003939 StrictModeFlag strict_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003940 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003941
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003942 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003943 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003944 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003945 isolate->factory()->NewTypeError("non_object_property_store",
3946 HandleVector(args, 2));
3947 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003948 }
3949
3950 // If the object isn't a JavaScript object, we ignore the store.
3951 if (!object->IsJSObject()) return *value;
3952
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003953 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
3954
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003955 // Check if the given key is an array index.
3956 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003957 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003958 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
3959 // of a string using [] notation. We need to support this too in
3960 // JavaScript.
3961 // In the case of a String object we just need to redirect the assignment to
3962 // the underlying string if the index is in range. Since the underlying
3963 // string does nothing with the assignment then we can ignore such
3964 // assignments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003965 if (js_object->IsStringObjectWithCharacterAt(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003966 return *value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003967 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003968
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003969 Handle<Object> result = SetElement(js_object, index, value, strict_mode);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003970 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003971 return *value;
3972 }
3973
3974 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003975 Handle<Object> result;
3976 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003977 result = SetElement(js_object, index, value, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003978 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003979 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003980 key_string->TryFlatten();
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003981 result = SetProperty(js_object, key_string, value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003982 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003983 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003984 return *value;
3985 }
3986
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003987 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003988 bool has_pending_exception = false;
3989 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
3990 if (has_pending_exception) return Failure::Exception();
3991 Handle<String> name = Handle<String>::cast(converted);
3992
3993 if (name->AsArrayIndex(&index)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003994 return js_object->SetElement(index, *value, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003995 } else {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003996 return js_object->SetProperty(*name, *value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003997 }
3998}
3999
4000
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004001MaybeObject* Runtime::ForceSetObjectProperty(Isolate* isolate,
4002 Handle<JSObject> js_object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004003 Handle<Object> key,
4004 Handle<Object> value,
4005 PropertyAttributes attr) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004006 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004007
4008 // Check if the given key is an array index.
4009 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004010 if (key->ToArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004011 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4012 // of a string using [] notation. We need to support this too in
4013 // JavaScript.
4014 // In the case of a String object we just need to redirect the assignment to
4015 // the underlying string if the index is in range. Since the underlying
4016 // string does nothing with the assignment then we can ignore such
4017 // assignments.
4018 if (js_object->IsStringObjectWithCharacterAt(index)) {
4019 return *value;
4020 }
4021
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004022 return js_object->SetElement(index, *value, kNonStrictMode);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004023 }
4024
4025 if (key->IsString()) {
4026 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004027 return js_object->SetElement(index, *value, kNonStrictMode);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004028 } else {
4029 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004030 key_string->TryFlatten();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004031 return js_object->SetLocalPropertyIgnoreAttributes(*key_string,
4032 *value,
4033 attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004034 }
4035 }
4036
4037 // Call-back into JavaScript to convert the key to a string.
4038 bool has_pending_exception = false;
4039 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4040 if (has_pending_exception) return Failure::Exception();
4041 Handle<String> name = Handle<String>::cast(converted);
4042
4043 if (name->AsArrayIndex(&index)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004044 return js_object->SetElement(index, *value, kNonStrictMode);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004045 } else {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004046 return js_object->SetLocalPropertyIgnoreAttributes(*name, *value, attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004047 }
4048}
4049
4050
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004051MaybeObject* Runtime::ForceDeleteObjectProperty(Isolate* isolate,
4052 Handle<JSObject> js_object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004053 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004054 HandleScope scope(isolate);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004055
4056 // Check if the given key is an array index.
4057 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004058 if (key->ToArrayIndex(&index)) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00004059 // In Firefox/SpiderMonkey, Safari and Opera you can access the
4060 // characters of a string using [] notation. In the case of a
4061 // String object we just need to redirect the deletion to the
4062 // underlying string if the index is in range. Since the
4063 // underlying string does nothing with the deletion, we can ignore
4064 // such deletions.
4065 if (js_object->IsStringObjectWithCharacterAt(index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004066 return isolate->heap()->true_value();
ager@chromium.orge2902be2009-06-08 12:21:35 +00004067 }
4068
4069 return js_object->DeleteElement(index, JSObject::FORCE_DELETION);
4070 }
4071
4072 Handle<String> key_string;
4073 if (key->IsString()) {
4074 key_string = Handle<String>::cast(key);
4075 } else {
4076 // Call-back into JavaScript to convert the key to a string.
4077 bool has_pending_exception = false;
4078 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4079 if (has_pending_exception) return Failure::Exception();
4080 key_string = Handle<String>::cast(converted);
4081 }
4082
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004083 key_string->TryFlatten();
ager@chromium.orge2902be2009-06-08 12:21:35 +00004084 return js_object->DeleteProperty(*key_string, JSObject::FORCE_DELETION);
4085}
4086
4087
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004088RUNTIME_FUNCTION(MaybeObject*, Runtime_SetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004089 NoHandleAllocation ha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004090 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004091
4092 Handle<Object> object = args.at<Object>(0);
4093 Handle<Object> key = args.at<Object>(1);
4094 Handle<Object> value = args.at<Object>(2);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004095 CONVERT_SMI_CHECKED(unchecked_attributes, args[3]);
4096 RUNTIME_ASSERT(
4097 (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004098 // Compute attributes.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004099 PropertyAttributes attributes =
4100 static_cast<PropertyAttributes>(unchecked_attributes);
4101
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004102 StrictModeFlag strict_mode = kNonStrictMode;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004103 if (args.length() == 5) {
4104 CONVERT_SMI_CHECKED(strict_unchecked, args[4]);
4105 RUNTIME_ASSERT(strict_unchecked == kStrictMode ||
4106 strict_unchecked == kNonStrictMode);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004107 strict_mode = static_cast<StrictModeFlag>(strict_unchecked);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004108 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004109
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004110 return Runtime::SetObjectProperty(isolate,
4111 object,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004112 key,
4113 value,
4114 attributes,
4115 strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004116}
4117
4118
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004119// Set the native flag on the function.
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004120// This is used to decide if we should transform null and undefined
4121// into the global object when doing call and apply.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004122RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNativeFlag) {
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004123 NoHandleAllocation ha;
4124 RUNTIME_ASSERT(args.length() == 1);
4125
4126 Handle<Object> object = args.at<Object>(0);
4127
4128 if (object->IsJSFunction()) {
4129 JSFunction* func = JSFunction::cast(*object);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004130 func->shared()->set_native(true);
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004131 }
4132 return isolate->heap()->undefined_value();
4133}
4134
4135
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004136// Set a local property, even if it is READ_ONLY. If the property does not
4137// exist, it will be added with attributes NONE.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004138RUNTIME_FUNCTION(MaybeObject*, Runtime_IgnoreAttributesAndSetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004139 NoHandleAllocation ha;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004140 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004141 CONVERT_CHECKED(JSObject, object, args[0]);
4142 CONVERT_CHECKED(String, name, args[1]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004143 // Compute attributes.
4144 PropertyAttributes attributes = NONE;
4145 if (args.length() == 4) {
4146 CONVERT_CHECKED(Smi, value_obj, args[3]);
4147 int unchecked_value = value_obj->value();
4148 // Only attribute bits should be set.
4149 RUNTIME_ASSERT(
4150 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4151 attributes = static_cast<PropertyAttributes>(unchecked_value);
4152 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004153
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004154 return object->
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004155 SetLocalPropertyIgnoreAttributes(name, args[2], attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004156}
4157
4158
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004159RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004160 NoHandleAllocation ha;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004161 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004162
4163 CONVERT_CHECKED(JSObject, object, args[0]);
4164 CONVERT_CHECKED(String, key, args[1]);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004165 CONVERT_SMI_CHECKED(strict, args[2]);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004166 return object->DeleteProperty(key, (strict == kStrictMode)
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004167 ? JSObject::STRICT_DELETION
4168 : JSObject::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004169}
4170
4171
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004172static Object* HasLocalPropertyImplementation(Isolate* isolate,
4173 Handle<JSObject> object,
ager@chromium.org9085a012009-05-11 19:22:57 +00004174 Handle<String> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004175 if (object->HasLocalProperty(*key)) return isolate->heap()->true_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004176 // Handle hidden prototypes. If there's a hidden prototype above this thing
4177 // then we have to check it for properties, because they are supposed to
4178 // look like they are on this object.
4179 Handle<Object> proto(object->GetPrototype());
4180 if (proto->IsJSObject() &&
4181 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004182 return HasLocalPropertyImplementation(isolate,
4183 Handle<JSObject>::cast(proto),
4184 key);
ager@chromium.org9085a012009-05-11 19:22:57 +00004185 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004186 return isolate->heap()->false_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004187}
4188
4189
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004190RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLocalProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004191 NoHandleAllocation ha;
4192 ASSERT(args.length() == 2);
4193 CONVERT_CHECKED(String, key, args[1]);
4194
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004195 uint32_t index;
4196 const bool key_is_array_index = key->AsArrayIndex(&index);
4197
ager@chromium.org9085a012009-05-11 19:22:57 +00004198 Object* obj = args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004199 // Only JS objects can have properties.
ager@chromium.org9085a012009-05-11 19:22:57 +00004200 if (obj->IsJSObject()) {
4201 JSObject* object = JSObject::cast(obj);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004202 // Fast case: either the key is a real named property or it is not
4203 // an array index and there are no interceptors or hidden
4204 // prototypes.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004205 if (object->HasRealNamedProperty(key)) return isolate->heap()->true_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004206 Map* map = object->map();
4207 if (!key_is_array_index &&
4208 !map->has_named_interceptor() &&
4209 !HeapObject::cast(map->prototype())->map()->is_hidden_prototype()) {
4210 return isolate->heap()->false_value();
4211 }
4212 // Slow case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004213 HandleScope scope(isolate);
4214 return HasLocalPropertyImplementation(isolate,
4215 Handle<JSObject>(object),
ager@chromium.org9085a012009-05-11 19:22:57 +00004216 Handle<String>(key));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004217 } else if (obj->IsString() && key_is_array_index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004218 // Well, there is one exception: Handle [] on strings.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004219 String* string = String::cast(obj);
4220 if (index < static_cast<uint32_t>(string->length())) {
4221 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004222 }
4223 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004224 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004225}
4226
4227
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004228RUNTIME_FUNCTION(MaybeObject*, Runtime_HasProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004229 NoHandleAllocation na;
4230 ASSERT(args.length() == 2);
4231
4232 // Only JS objects can have properties.
4233 if (args[0]->IsJSObject()) {
4234 JSObject* object = JSObject::cast(args[0]);
4235 CONVERT_CHECKED(String, key, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004236 if (object->HasProperty(key)) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004237 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004238 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004239}
4240
4241
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004242RUNTIME_FUNCTION(MaybeObject*, Runtime_HasElement) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004243 NoHandleAllocation na;
4244 ASSERT(args.length() == 2);
4245
4246 // Only JS objects can have elements.
4247 if (args[0]->IsJSObject()) {
4248 JSObject* object = JSObject::cast(args[0]);
4249 CONVERT_CHECKED(Smi, index_obj, args[1]);
4250 uint32_t index = index_obj->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004251 if (object->HasElement(index)) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004252 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004253 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004254}
4255
4256
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004257RUNTIME_FUNCTION(MaybeObject*, Runtime_IsPropertyEnumerable) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004258 NoHandleAllocation ha;
4259 ASSERT(args.length() == 2);
4260
4261 CONVERT_CHECKED(JSObject, object, args[0]);
4262 CONVERT_CHECKED(String, key, args[1]);
4263
4264 uint32_t index;
4265 if (key->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004266 return isolate->heap()->ToBoolean(object->HasElement(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004267 }
4268
ager@chromium.org870a0b62008-11-04 11:43:05 +00004269 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004270 return isolate->heap()->ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004271}
4272
4273
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004274RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004275 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004276 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00004277 CONVERT_ARG_CHECKED(JSObject, object, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004278 return *GetKeysFor(object);
4279}
4280
4281
4282// Returns either a FixedArray as Runtime_GetPropertyNames,
4283// or, if the given object has an enum cache that contains
4284// all enumerable properties of the object and its prototypes
4285// have none, the map of the object. This is used to speed up
4286// the check for deletions during a for-in.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004287RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNamesFast) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004288 ASSERT(args.length() == 1);
4289
4290 CONVERT_CHECKED(JSObject, raw_object, args[0]);
4291
4292 if (raw_object->IsSimpleEnum()) return raw_object->map();
4293
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004294 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004295 Handle<JSObject> object(raw_object);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004296 Handle<FixedArray> content = GetKeysInFixedArrayFor(object,
4297 INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004298
4299 // Test again, since cache may have been built by preceding call.
4300 if (object->IsSimpleEnum()) return object->map();
4301
4302 return *content;
4303}
4304
4305
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004306// Find the length of the prototype chain that is to to handled as one. If a
4307// prototype object is hidden it is to be viewed as part of the the object it
4308// is prototype for.
4309static int LocalPrototypeChainLength(JSObject* obj) {
4310 int count = 1;
4311 Object* proto = obj->GetPrototype();
4312 while (proto->IsJSObject() &&
4313 JSObject::cast(proto)->map()->is_hidden_prototype()) {
4314 count++;
4315 proto = JSObject::cast(proto)->GetPrototype();
4316 }
4317 return count;
4318}
4319
4320
4321// Return the names of the local named properties.
4322// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004323RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004324 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004325 ASSERT(args.length() == 1);
4326 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004327 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004328 }
4329 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4330
4331 // Skip the global proxy as it has no properties and always delegates to the
4332 // real global object.
4333 if (obj->IsJSGlobalProxy()) {
4334 // Only collect names if access is permitted.
4335 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004336 !isolate->MayNamedAccess(*obj,
4337 isolate->heap()->undefined_value(),
4338 v8::ACCESS_KEYS)) {
4339 isolate->ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
4340 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004341 }
4342 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
4343 }
4344
4345 // Find the number of objects making up this.
4346 int length = LocalPrototypeChainLength(*obj);
4347
4348 // Find the number of local properties for each of the objects.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00004349 ScopedVector<int> local_property_count(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004350 int total_property_count = 0;
4351 Handle<JSObject> jsproto = obj;
4352 for (int i = 0; i < length; i++) {
4353 // Only collect names if access is permitted.
4354 if (jsproto->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004355 !isolate->MayNamedAccess(*jsproto,
4356 isolate->heap()->undefined_value(),
4357 v8::ACCESS_KEYS)) {
4358 isolate->ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
4359 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004360 }
4361 int n;
4362 n = jsproto->NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE));
4363 local_property_count[i] = n;
4364 total_property_count += n;
4365 if (i < length - 1) {
4366 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4367 }
4368 }
4369
4370 // Allocate an array with storage for all the property names.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004371 Handle<FixedArray> names =
4372 isolate->factory()->NewFixedArray(total_property_count);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004373
4374 // Get the property names.
4375 jsproto = obj;
4376 int proto_with_hidden_properties = 0;
4377 for (int i = 0; i < length; i++) {
4378 jsproto->GetLocalPropertyNames(*names,
4379 i == 0 ? 0 : local_property_count[i - 1]);
4380 if (!GetHiddenProperties(jsproto, false)->IsUndefined()) {
4381 proto_with_hidden_properties++;
4382 }
4383 if (i < length - 1) {
4384 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4385 }
4386 }
4387
4388 // Filter out name of hidden propeties object.
4389 if (proto_with_hidden_properties > 0) {
4390 Handle<FixedArray> old_names = names;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004391 names = isolate->factory()->NewFixedArray(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004392 names->length() - proto_with_hidden_properties);
4393 int dest_pos = 0;
4394 for (int i = 0; i < total_property_count; i++) {
4395 Object* name = old_names->get(i);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004396 if (name == isolate->heap()->hidden_symbol()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004397 continue;
4398 }
4399 names->set(dest_pos++, name);
4400 }
4401 }
4402
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004403 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004404}
4405
4406
4407// Return the names of the local indexed properties.
4408// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004409RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004410 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004411 ASSERT(args.length() == 1);
4412 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004413 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004414 }
4415 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4416
4417 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004418 Handle<FixedArray> names = isolate->factory()->NewFixedArray(n);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004419 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004420 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004421}
4422
4423
4424// Return information on whether an object has a named or indexed interceptor.
4425// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004426RUNTIME_FUNCTION(MaybeObject*, Runtime_GetInterceptorInfo) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004427 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004428 ASSERT(args.length() == 1);
4429 if (!args[0]->IsJSObject()) {
4430 return Smi::FromInt(0);
4431 }
4432 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4433
4434 int result = 0;
4435 if (obj->HasNamedInterceptor()) result |= 2;
4436 if (obj->HasIndexedInterceptor()) result |= 1;
4437
4438 return Smi::FromInt(result);
4439}
4440
4441
4442// Return property names from named interceptor.
4443// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004444RUNTIME_FUNCTION(MaybeObject*, Runtime_GetNamedInterceptorPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004445 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004446 ASSERT(args.length() == 1);
4447 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4448
4449 if (obj->HasNamedInterceptor()) {
4450 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
4451 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4452 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004453 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004454}
4455
4456
4457// Return element names from indexed interceptor.
4458// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004459RUNTIME_FUNCTION(MaybeObject*, Runtime_GetIndexedInterceptorElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004460 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004461 ASSERT(args.length() == 1);
4462 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4463
4464 if (obj->HasIndexedInterceptor()) {
4465 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
4466 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4467 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004468 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004469}
4470
4471
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004472RUNTIME_FUNCTION(MaybeObject*, Runtime_LocalKeys) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004473 ASSERT_EQ(args.length(), 1);
4474 CONVERT_CHECKED(JSObject, raw_object, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004475 HandleScope scope(isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004476 Handle<JSObject> object(raw_object);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004477
4478 if (object->IsJSGlobalProxy()) {
ricow@chromium.org65001782011-02-15 13:36:41 +00004479 // Do access checks before going to the global object.
4480 if (object->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004481 !isolate->MayNamedAccess(*object, isolate->heap()->undefined_value(),
ricow@chromium.org65001782011-02-15 13:36:41 +00004482 v8::ACCESS_KEYS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004483 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_KEYS);
4484 return *isolate->factory()->NewJSArray(0);
ricow@chromium.org65001782011-02-15 13:36:41 +00004485 }
4486
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004487 Handle<Object> proto(object->GetPrototype());
4488 // If proxy is detached we simply return an empty array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004489 if (proto->IsNull()) return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004490 object = Handle<JSObject>::cast(proto);
4491 }
4492
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004493 Handle<FixedArray> contents = GetKeysInFixedArrayFor(object,
4494 LOCAL_ONLY);
4495 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
4496 // property array and since the result is mutable we have to create
4497 // a fresh clone on each invocation.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004498 int length = contents->length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004499 Handle<FixedArray> copy = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004500 for (int i = 0; i < length; i++) {
4501 Object* entry = contents->get(i);
4502 if (entry->IsString()) {
4503 copy->set(i, entry);
4504 } else {
4505 ASSERT(entry->IsNumber());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004506 HandleScope scope(isolate);
4507 Handle<Object> entry_handle(entry, isolate);
4508 Handle<Object> entry_str =
4509 isolate->factory()->NumberToString(entry_handle);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004510 copy->set(i, *entry_str);
4511 }
4512 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004513 return *isolate->factory()->NewJSArrayWithElements(copy);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004514}
4515
4516
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004517RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArgumentsProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004518 NoHandleAllocation ha;
4519 ASSERT(args.length() == 1);
4520
4521 // Compute the frame holding the arguments.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00004522 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004523 it.AdvanceToArgumentsFrame();
4524 JavaScriptFrame* frame = it.frame();
4525
4526 // Get the actual number of provided arguments.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00004527 const uint32_t n = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004528
4529 // Try to convert the key to an index. If successful and within
4530 // index return the the argument from the frame.
4531 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004532 if (args[0]->ToArrayIndex(&index) && index < n) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004533 return frame->GetParameter(index);
4534 }
4535
4536 // Convert the key to a string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004537 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004538 bool exception = false;
4539 Handle<Object> converted =
4540 Execution::ToString(args.at<Object>(0), &exception);
4541 if (exception) return Failure::Exception();
4542 Handle<String> key = Handle<String>::cast(converted);
4543
4544 // Try to convert the string key into an array index.
4545 if (key->AsArrayIndex(&index)) {
4546 if (index < n) {
4547 return frame->GetParameter(index);
4548 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004549 return isolate->initial_object_prototype()->GetElement(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004550 }
4551 }
4552
4553 // Handle special arguments properties.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004554 if (key->Equals(isolate->heap()->length_symbol())) return Smi::FromInt(n);
4555 if (key->Equals(isolate->heap()->callee_symbol())) {
4556 Object* function = frame->function();
4557 if (function->IsJSFunction() &&
4558 JSFunction::cast(function)->shared()->strict_mode()) {
4559 return isolate->Throw(*isolate->factory()->NewTypeError(
4560 "strict_arguments_callee", HandleVector<Object>(NULL, 0)));
4561 }
4562 return function;
4563 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004564
4565 // Lookup in the initial Object.prototype object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004566 return isolate->initial_object_prototype()->GetProperty(*key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004567}
4568
4569
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004570RUNTIME_FUNCTION(MaybeObject*, Runtime_ToFastProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004571 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004572
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004573 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004574 Handle<Object> object = args.at<Object>(0);
4575 if (object->IsJSObject()) {
4576 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
ager@chromium.org5c838252010-02-19 08:53:10 +00004577 if (!js_object->HasFastProperties() && !js_object->IsGlobalObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004578 MaybeObject* ok = js_object->TransformToFastProperties(0);
4579 if (ok->IsRetryAfterGC()) return ok;
ager@chromium.org5c838252010-02-19 08:53:10 +00004580 }
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004581 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004582 return *object;
4583}
4584
4585
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004586RUNTIME_FUNCTION(MaybeObject*, Runtime_ToSlowProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004587 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004588
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004589 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004590 Handle<Object> object = args.at<Object>(0);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004591 if (object->IsJSObject() && !object->IsJSGlobalProxy()) {
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004592 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004593 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004594 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004595 return *object;
4596}
4597
4598
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004599RUNTIME_FUNCTION(MaybeObject*, Runtime_ToBool) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004600 NoHandleAllocation ha;
4601 ASSERT(args.length() == 1);
4602
4603 return args[0]->ToBoolean();
4604}
4605
4606
4607// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
4608// Possible optimizations: put the type string into the oddballs.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004609RUNTIME_FUNCTION(MaybeObject*, Runtime_Typeof) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004610 NoHandleAllocation ha;
4611
4612 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004613 if (obj->IsNumber()) return isolate->heap()->number_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004614 HeapObject* heap_obj = HeapObject::cast(obj);
4615
4616 // typeof an undetectable object is 'undefined'
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004617 if (heap_obj->map()->is_undetectable()) {
4618 return isolate->heap()->undefined_symbol();
4619 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004620
4621 InstanceType instance_type = heap_obj->map()->instance_type();
4622 if (instance_type < FIRST_NONSTRING_TYPE) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004623 return isolate->heap()->string_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004624 }
4625
4626 switch (instance_type) {
4627 case ODDBALL_TYPE:
4628 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004629 return isolate->heap()->boolean_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004630 }
4631 if (heap_obj->IsNull()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004632 return isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004633 }
4634 ASSERT(heap_obj->IsUndefined());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004635 return isolate->heap()->undefined_symbol();
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00004636 case JS_FUNCTION_TYPE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004637 return isolate->heap()->function_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004638 default:
4639 // For any kind of object not handled above, the spec rule for
4640 // host objects gives that it is okay to return "object"
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004641 return isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004642 }
4643}
4644
4645
lrn@chromium.org25156de2010-04-06 13:10:27 +00004646static bool AreDigits(const char*s, int from, int to) {
4647 for (int i = from; i < to; i++) {
4648 if (s[i] < '0' || s[i] > '9') return false;
4649 }
4650
4651 return true;
4652}
4653
4654
4655static int ParseDecimalInteger(const char*s, int from, int to) {
4656 ASSERT(to - from < 10); // Overflow is not possible.
4657 ASSERT(from < to);
4658 int d = s[from] - '0';
4659
4660 for (int i = from + 1; i < to; i++) {
4661 d = 10 * d + (s[i] - '0');
4662 }
4663
4664 return d;
4665}
4666
4667
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004668RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004669 NoHandleAllocation ha;
4670 ASSERT(args.length() == 1);
4671 CONVERT_CHECKED(String, subject, args[0]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004672 subject->TryFlatten();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004673
4674 // Fast case: short integer or some sorts of junk values.
4675 int len = subject->length();
4676 if (subject->IsSeqAsciiString()) {
4677 if (len == 0) return Smi::FromInt(0);
4678
4679 char const* data = SeqAsciiString::cast(subject)->GetChars();
4680 bool minus = (data[0] == '-');
4681 int start_pos = (minus ? 1 : 0);
4682
4683 if (start_pos == len) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004684 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004685 } else if (data[start_pos] > '9') {
4686 // Fast check for a junk value. A valid string may start from a
4687 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
4688 // the 'I' character ('Infinity'). All of that have codes not greater than
4689 // '9' except 'I'.
4690 if (data[start_pos] != 'I') {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004691 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004692 }
4693 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
4694 // The maximal/minimal smi has 10 digits. If the string has less digits we
4695 // know it will fit into the smi-data type.
4696 int d = ParseDecimalInteger(data, start_pos, len);
4697 if (minus) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004698 if (d == 0) return isolate->heap()->minus_zero_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004699 d = -d;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004700 } else if (!subject->HasHashCode() &&
4701 len <= String::kMaxArrayIndexSize &&
4702 (len == 1 || data[0] != '0')) {
4703 // String hash is not calculated yet but all the data are present.
4704 // Update the hash field to speed up sequential convertions.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00004705 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004706#ifdef DEBUG
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004707 subject->Hash(); // Force hash calculation.
4708 ASSERT_EQ(static_cast<int>(subject->hash_field()),
4709 static_cast<int>(hash));
4710#endif
4711 subject->set_hash_field(hash);
lrn@chromium.org25156de2010-04-06 13:10:27 +00004712 }
4713 return Smi::FromInt(d);
4714 }
4715 }
4716
4717 // Slower case.
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00004718 return isolate->heap()->NumberFromDouble(
4719 StringToDouble(isolate->unicode_cache(), subject, ALLOW_HEX));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004720}
4721
4722
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004723RUNTIME_FUNCTION(MaybeObject*, Runtime_StringFromCharCodeArray) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004724 NoHandleAllocation ha;
4725 ASSERT(args.length() == 1);
4726
4727 CONVERT_CHECKED(JSArray, codes, args[0]);
4728 int length = Smi::cast(codes->length())->value();
4729
4730 // Check if the string can be ASCII.
4731 int i;
4732 for (i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004733 Object* element;
4734 { MaybeObject* maybe_element = codes->GetElement(i);
4735 // We probably can't get an exception here, but just in order to enforce
4736 // the checking of inputs in the runtime calls we check here.
4737 if (!maybe_element->ToObject(&element)) return maybe_element;
4738 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004739 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
4740 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
4741 break;
4742 }
4743
lrn@chromium.org303ada72010-10-27 09:33:13 +00004744 MaybeObject* maybe_object = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004745 if (i == length) { // The string is ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004746 maybe_object = isolate->heap()->AllocateRawAsciiString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004747 } else { // The string is not ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004748 maybe_object = isolate->heap()->AllocateRawTwoByteString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004749 }
4750
lrn@chromium.org303ada72010-10-27 09:33:13 +00004751 Object* object = NULL;
4752 if (!maybe_object->ToObject(&object)) return maybe_object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004753 String* result = String::cast(object);
4754 for (int i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004755 Object* element;
4756 { MaybeObject* maybe_element = codes->GetElement(i);
4757 if (!maybe_element->ToObject(&element)) return maybe_element;
4758 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004759 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004760 result->Set(i, chr & 0xffff);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004761 }
4762 return result;
4763}
4764
4765
4766// kNotEscaped is generated by the following:
4767//
4768// #!/bin/perl
4769// for (my $i = 0; $i < 256; $i++) {
4770// print "\n" if $i % 16 == 0;
4771// my $c = chr($i);
4772// my $escaped = 1;
4773// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
4774// print $escaped ? "0, " : "1, ";
4775// }
4776
4777
4778static bool IsNotEscaped(uint16_t character) {
4779 // Only for 8 bit characters, the rest are always escaped (in a different way)
4780 ASSERT(character < 256);
4781 static const char kNotEscaped[256] = {
4782 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4783 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4784 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
4785 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
4786 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4787 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
4788 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4789 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
4790 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4791 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4792 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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 };
4799 return kNotEscaped[character] != 0;
4800}
4801
4802
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004803RUNTIME_FUNCTION(MaybeObject*, Runtime_URIEscape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004804 const char hex_chars[] = "0123456789ABCDEF";
4805 NoHandleAllocation ha;
4806 ASSERT(args.length() == 1);
4807 CONVERT_CHECKED(String, source, args[0]);
4808
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004809 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004810
4811 int escaped_length = 0;
4812 int length = source->length();
4813 {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004814 Access<StringInputBuffer> buffer(
4815 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004816 buffer->Reset(source);
4817 while (buffer->has_more()) {
4818 uint16_t character = buffer->GetNext();
4819 if (character >= 256) {
4820 escaped_length += 6;
4821 } else if (IsNotEscaped(character)) {
4822 escaped_length++;
4823 } else {
4824 escaped_length += 3;
4825 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004826 // We don't allow strings that are longer than a maximal length.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004827 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004828 if (escaped_length > String::kMaxLength) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004829 isolate->context()->mark_out_of_memory();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004830 return Failure::OutOfMemoryException();
4831 }
4832 }
4833 }
4834 // No length change implies no change. Return original string if no change.
4835 if (escaped_length == length) {
4836 return source;
4837 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00004838 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004839 { MaybeObject* maybe_o =
4840 isolate->heap()->AllocateRawAsciiString(escaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004841 if (!maybe_o->ToObject(&o)) return maybe_o;
4842 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004843 String* destination = String::cast(o);
4844 int dest_position = 0;
4845
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004846 Access<StringInputBuffer> buffer(
4847 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004848 buffer->Rewind();
4849 while (buffer->has_more()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00004850 uint16_t chr = buffer->GetNext();
4851 if (chr >= 256) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004852 destination->Set(dest_position, '%');
4853 destination->Set(dest_position+1, 'u');
4854 destination->Set(dest_position+2, hex_chars[chr >> 12]);
4855 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]);
4856 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]);
4857 destination->Set(dest_position+5, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004858 dest_position += 6;
ager@chromium.org870a0b62008-11-04 11:43:05 +00004859 } else if (IsNotEscaped(chr)) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004860 destination->Set(dest_position, chr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004861 dest_position++;
4862 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004863 destination->Set(dest_position, '%');
4864 destination->Set(dest_position+1, hex_chars[chr >> 4]);
4865 destination->Set(dest_position+2, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004866 dest_position += 3;
4867 }
4868 }
4869 return destination;
4870}
4871
4872
4873static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
4874 static const signed char kHexValue['g'] = {
4875 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4876 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4877 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4878 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
4879 -1, 10, 11, 12, 13, 14, 15, -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 -1, 10, 11, 12, 13, 14, 15 };
4882
4883 if (character1 > 'f') return -1;
4884 int hi = kHexValue[character1];
4885 if (hi == -1) return -1;
4886 if (character2 > 'f') return -1;
4887 int lo = kHexValue[character2];
4888 if (lo == -1) return -1;
4889 return (hi << 4) + lo;
4890}
4891
4892
ager@chromium.org870a0b62008-11-04 11:43:05 +00004893static inline int Unescape(String* source,
ager@chromium.org870a0b62008-11-04 11:43:05 +00004894 int i,
4895 int length,
4896 int* step) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004897 uint16_t character = source->Get(i);
ager@chromium.org870a0b62008-11-04 11:43:05 +00004898 int32_t hi = 0;
4899 int32_t lo = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004900 if (character == '%' &&
4901 i <= length - 6 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004902 source->Get(i + 1) == 'u' &&
4903 (hi = TwoDigitHex(source->Get(i + 2),
4904 source->Get(i + 3))) != -1 &&
4905 (lo = TwoDigitHex(source->Get(i + 4),
4906 source->Get(i + 5))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004907 *step = 6;
4908 return (hi << 8) + lo;
4909 } else if (character == '%' &&
4910 i <= length - 3 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004911 (lo = TwoDigitHex(source->Get(i + 1),
4912 source->Get(i + 2))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004913 *step = 3;
4914 return lo;
4915 } else {
4916 *step = 1;
4917 return character;
4918 }
4919}
4920
4921
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004922RUNTIME_FUNCTION(MaybeObject*, Runtime_URIUnescape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004923 NoHandleAllocation ha;
4924 ASSERT(args.length() == 1);
4925 CONVERT_CHECKED(String, source, args[0]);
4926
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004927 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004928
4929 bool ascii = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004930 int length = source->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004931
4932 int unescaped_length = 0;
4933 for (int i = 0; i < length; unescaped_length++) {
4934 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004935 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004936 ascii = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004937 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004938 i += step;
4939 }
4940
4941 // No length change implies no change. Return original string if no change.
4942 if (unescaped_length == length)
4943 return source;
4944
lrn@chromium.org303ada72010-10-27 09:33:13 +00004945 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004946 { MaybeObject* maybe_o =
4947 ascii ?
4948 isolate->heap()->AllocateRawAsciiString(unescaped_length) :
4949 isolate->heap()->AllocateRawTwoByteString(unescaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004950 if (!maybe_o->ToObject(&o)) return maybe_o;
4951 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004952 String* destination = String::cast(o);
4953
4954 int dest_position = 0;
4955 for (int i = 0; i < length; dest_position++) {
4956 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004957 destination->Set(dest_position, Unescape(source, i, length, &step));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004958 i += step;
4959 }
4960 return destination;
4961}
4962
4963
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004964static const unsigned int kQuoteTableLength = 128u;
4965
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004966static const int kJsonQuotesCharactersPerEntry = 8;
4967static const char* const JsonQuotes =
4968 "\\u0000 \\u0001 \\u0002 \\u0003 "
4969 "\\u0004 \\u0005 \\u0006 \\u0007 "
4970 "\\b \\t \\n \\u000b "
4971 "\\f \\r \\u000e \\u000f "
4972 "\\u0010 \\u0011 \\u0012 \\u0013 "
4973 "\\u0014 \\u0015 \\u0016 \\u0017 "
4974 "\\u0018 \\u0019 \\u001a \\u001b "
4975 "\\u001c \\u001d \\u001e \\u001f "
4976 " ! \\\" # "
4977 "$ % & ' "
4978 "( ) * + "
4979 ", - . / "
4980 "0 1 2 3 "
4981 "4 5 6 7 "
4982 "8 9 : ; "
4983 "< = > ? "
4984 "@ A B C "
4985 "D E F G "
4986 "H I J K "
4987 "L M N O "
4988 "P Q R S "
4989 "T U V W "
4990 "X Y Z [ "
4991 "\\\\ ] ^ _ "
4992 "` a b c "
4993 "d e f g "
4994 "h i j k "
4995 "l m n o "
4996 "p q r s "
4997 "t u v w "
4998 "x y z { "
4999 "| } ~ \177 ";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005000
5001
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005002// For a string that is less than 32k characters it should always be
5003// possible to allocate it in new space.
5004static const int kMaxGuaranteedNewSpaceString = 32 * 1024;
5005
5006
5007// Doing JSON quoting cannot make the string more than this many times larger.
5008static const int kJsonQuoteWorstCaseBlowup = 6;
5009
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005010static const int kSpaceForQuotesAndComma = 3;
5011static const int kSpaceForBrackets = 2;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005012
5013// Covers the entire ASCII range (all other characters are unchanged by JSON
5014// quoting).
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005015static const byte JsonQuoteLengths[kQuoteTableLength] = {
5016 6, 6, 6, 6, 6, 6, 6, 6,
5017 2, 2, 2, 6, 2, 2, 6, 6,
5018 6, 6, 6, 6, 6, 6, 6, 6,
5019 6, 6, 6, 6, 6, 6, 6, 6,
5020 1, 1, 2, 1, 1, 1, 1, 1,
5021 1, 1, 1, 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, 2, 1, 1, 1,
5028 1, 1, 1, 1, 1, 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};
5033
5034
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005035template <typename StringType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005036MaybeObject* AllocateRawString(Isolate* isolate, int length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005037
5038
5039template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005040MaybeObject* AllocateRawString<SeqTwoByteString>(Isolate* isolate, int length) {
5041 return isolate->heap()->AllocateRawTwoByteString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005042}
5043
5044
5045template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005046MaybeObject* AllocateRawString<SeqAsciiString>(Isolate* isolate, int length) {
5047 return isolate->heap()->AllocateRawAsciiString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005048}
5049
5050
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005051template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005052static MaybeObject* SlowQuoteJsonString(Isolate* isolate,
5053 Vector<const Char> characters) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005054 int length = characters.length();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005055 const Char* read_cursor = characters.start();
5056 const Char* end = read_cursor + length;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005057 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005058 int quoted_length = kSpaceForQuotes;
5059 while (read_cursor < end) {
5060 Char c = *(read_cursor++);
5061 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5062 quoted_length++;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005063 } else {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005064 quoted_length += JsonQuoteLengths[static_cast<unsigned>(c)];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005065 }
5066 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005067 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5068 quoted_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005069 Object* new_object;
5070 if (!new_alloc->ToObject(&new_object)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005071 return new_alloc;
5072 }
5073 StringType* new_string = StringType::cast(new_object);
5074
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005075 Char* write_cursor = reinterpret_cast<Char*>(
5076 new_string->address() + SeqAsciiString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005077 if (comma) *(write_cursor++) = ',';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005078 *(write_cursor++) = '"';
5079
5080 read_cursor = characters.start();
5081 while (read_cursor < end) {
5082 Char c = *(read_cursor++);
5083 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5084 *(write_cursor++) = c;
5085 } else {
5086 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5087 const char* replacement = JsonQuotes +
5088 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5089 for (int i = 0; i < len; i++) {
5090 *write_cursor++ = *replacement++;
5091 }
5092 }
5093 }
5094 *(write_cursor++) = '"';
5095 return new_string;
5096}
5097
5098
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005099template <typename SinkChar, typename SourceChar>
5100static inline SinkChar* WriteQuoteJsonString(
5101 Isolate* isolate,
5102 SinkChar* write_cursor,
5103 Vector<const SourceChar> characters) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00005104 // SinkChar is only char if SourceChar is guaranteed to be char.
5105 ASSERT(sizeof(SinkChar) >= sizeof(SourceChar));
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005106 const SourceChar* read_cursor = characters.start();
5107 const SourceChar* end = read_cursor + characters.length();
5108 *(write_cursor++) = '"';
5109 while (read_cursor < end) {
5110 SourceChar c = *(read_cursor++);
5111 if (sizeof(SourceChar) > 1u &&
5112 static_cast<unsigned>(c) >= kQuoteTableLength) {
5113 *(write_cursor++) = static_cast<SinkChar>(c);
5114 } else {
5115 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5116 const char* replacement = JsonQuotes +
5117 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5118 write_cursor[0] = replacement[0];
5119 if (len > 1) {
5120 write_cursor[1] = replacement[1];
5121 if (len > 2) {
5122 ASSERT(len == 6);
5123 write_cursor[2] = replacement[2];
5124 write_cursor[3] = replacement[3];
5125 write_cursor[4] = replacement[4];
5126 write_cursor[5] = replacement[5];
5127 }
5128 }
5129 write_cursor += len;
5130 }
5131 }
5132 *(write_cursor++) = '"';
5133 return write_cursor;
5134}
5135
5136
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005137template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005138static MaybeObject* QuoteJsonString(Isolate* isolate,
5139 Vector<const Char> characters) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005140 int length = characters.length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005141 isolate->counters()->quote_json_char_count()->Increment(length);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005142 int worst_case_length =
5143 length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotesAndComma;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005144 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005145 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005146 }
5147
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005148 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5149 worst_case_length);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005150 Object* new_object;
5151 if (!new_alloc->ToObject(&new_object)) {
5152 return new_alloc;
5153 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005154 if (!isolate->heap()->new_space()->Contains(new_object)) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005155 // Even if our string is small enough to fit in new space we still have to
5156 // handle it being allocated in old space as may happen in the third
5157 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5158 // CEntryStub::GenerateCore.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005159 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005160 }
5161 StringType* new_string = StringType::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005162 ASSERT(isolate->heap()->new_space()->Contains(new_string));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005163
5164 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize);
5165 Char* write_cursor = reinterpret_cast<Char*>(
5166 new_string->address() + SeqAsciiString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005167 if (comma) *(write_cursor++) = ',';
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005168 write_cursor = WriteQuoteJsonString<Char, Char>(isolate,
5169 write_cursor,
5170 characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005171 int final_length = static_cast<int>(
5172 write_cursor - reinterpret_cast<Char*>(
5173 new_string->address() + SeqAsciiString::kHeaderSize));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005174 isolate->heap()->new_space()->
5175 template ShrinkStringAtAllocationBoundary<StringType>(
5176 new_string, final_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005177 return new_string;
5178}
5179
5180
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005181RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONString) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005182 NoHandleAllocation ha;
5183 CONVERT_CHECKED(String, str, args[0]);
5184 if (!str->IsFlat()) {
5185 MaybeObject* try_flatten = str->TryFlatten();
5186 Object* flat;
5187 if (!try_flatten->ToObject(&flat)) {
5188 return try_flatten;
5189 }
5190 str = String::cast(flat);
5191 ASSERT(str->IsFlat());
5192 }
5193 if (str->IsTwoByteRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005194 return QuoteJsonString<uc16, SeqTwoByteString, false>(isolate,
5195 str->ToUC16Vector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005196 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005197 return QuoteJsonString<char, SeqAsciiString, false>(isolate,
5198 str->ToAsciiVector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005199 }
5200}
5201
5202
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005203RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringComma) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005204 NoHandleAllocation ha;
5205 CONVERT_CHECKED(String, str, args[0]);
5206 if (!str->IsFlat()) {
5207 MaybeObject* try_flatten = str->TryFlatten();
5208 Object* flat;
5209 if (!try_flatten->ToObject(&flat)) {
5210 return try_flatten;
5211 }
5212 str = String::cast(flat);
5213 ASSERT(str->IsFlat());
5214 }
5215 if (str->IsTwoByteRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005216 return QuoteJsonString<uc16, SeqTwoByteString, true>(isolate,
5217 str->ToUC16Vector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005218 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005219 return QuoteJsonString<char, SeqAsciiString, true>(isolate,
5220 str->ToAsciiVector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005221 }
5222}
5223
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005224
5225template <typename Char, typename StringType>
5226static MaybeObject* QuoteJsonStringArray(Isolate* isolate,
5227 FixedArray* array,
5228 int worst_case_length) {
5229 int length = array->length();
5230
5231 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5232 worst_case_length);
5233 Object* new_object;
5234 if (!new_alloc->ToObject(&new_object)) {
5235 return new_alloc;
5236 }
5237 if (!isolate->heap()->new_space()->Contains(new_object)) {
5238 // Even if our string is small enough to fit in new space we still have to
5239 // handle it being allocated in old space as may happen in the third
5240 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5241 // CEntryStub::GenerateCore.
5242 return isolate->heap()->undefined_value();
5243 }
5244 AssertNoAllocation no_gc;
5245 StringType* new_string = StringType::cast(new_object);
5246 ASSERT(isolate->heap()->new_space()->Contains(new_string));
5247
5248 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize);
5249 Char* write_cursor = reinterpret_cast<Char*>(
5250 new_string->address() + SeqAsciiString::kHeaderSize);
5251 *(write_cursor++) = '[';
5252 for (int i = 0; i < length; i++) {
5253 if (i != 0) *(write_cursor++) = ',';
5254 String* str = String::cast(array->get(i));
5255 if (str->IsTwoByteRepresentation()) {
5256 write_cursor = WriteQuoteJsonString<Char, uc16>(isolate,
5257 write_cursor,
5258 str->ToUC16Vector());
5259 } else {
5260 write_cursor = WriteQuoteJsonString<Char, char>(isolate,
5261 write_cursor,
5262 str->ToAsciiVector());
5263 }
5264 }
5265 *(write_cursor++) = ']';
5266
5267 int final_length = static_cast<int>(
5268 write_cursor - reinterpret_cast<Char*>(
5269 new_string->address() + SeqAsciiString::kHeaderSize));
5270 isolate->heap()->new_space()->
5271 template ShrinkStringAtAllocationBoundary<StringType>(
5272 new_string, final_length);
5273 return new_string;
5274}
5275
5276
5277RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringArray) {
5278 NoHandleAllocation ha;
5279 ASSERT(args.length() == 1);
5280 CONVERT_CHECKED(JSArray, array, args[0]);
5281
5282 if (!array->HasFastElements()) return isolate->heap()->undefined_value();
5283 FixedArray* elements = FixedArray::cast(array->elements());
5284 int n = elements->length();
5285 bool ascii = true;
5286 int total_length = 0;
5287
5288 for (int i = 0; i < n; i++) {
5289 Object* elt = elements->get(i);
5290 if (!elt->IsString()) return isolate->heap()->undefined_value();
5291 String* element = String::cast(elt);
5292 if (!element->IsFlat()) return isolate->heap()->undefined_value();
5293 total_length += element->length();
5294 if (ascii && element->IsTwoByteRepresentation()) {
5295 ascii = false;
5296 }
5297 }
5298
5299 int worst_case_length =
5300 kSpaceForBrackets + n * kSpaceForQuotesAndComma
5301 + total_length * kJsonQuoteWorstCaseBlowup;
5302
5303 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
5304 return isolate->heap()->undefined_value();
5305 }
5306
5307 if (ascii) {
5308 return QuoteJsonStringArray<char, SeqAsciiString>(isolate,
5309 elements,
5310 worst_case_length);
5311 } else {
5312 return QuoteJsonStringArray<uc16, SeqTwoByteString>(isolate,
5313 elements,
5314 worst_case_length);
5315 }
5316}
5317
5318
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005319RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseInt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005320 NoHandleAllocation ha;
5321
5322 CONVERT_CHECKED(String, s, args[0]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005323 CONVERT_SMI_CHECKED(radix, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005324
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005325 s->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005326
lrn@chromium.org25156de2010-04-06 13:10:27 +00005327 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005328 double value = StringToInt(isolate->unicode_cache(), s, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005329 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005330}
5331
5332
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005333RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseFloat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005334 NoHandleAllocation ha;
5335 CONVERT_CHECKED(String, str, args[0]);
5336
5337 // ECMA-262 section 15.1.2.3, empty string is NaN
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005338 double value = StringToDouble(isolate->unicode_cache(),
5339 str, ALLOW_TRAILING_JUNK, OS::nan_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005340
5341 // Create a number object from the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005342 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005343}
5344
5345
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005346template <class Converter>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005347MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005348 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00005349 String* s,
5350 int length,
5351 int input_string_length,
5352 unibrow::Mapping<Converter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005353 // We try this twice, once with the assumption that the result is no longer
5354 // than the input and, if that assumption breaks, again with the exact
5355 // length. This may not be pretty, but it is nicer than what was here before
5356 // and I hereby claim my vaffel-is.
5357 //
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005358 // Allocate the resulting string.
5359 //
5360 // NOTE: This assumes that the upper/lower case of an ascii
5361 // character is also ascii. This is currently the case, but it
5362 // might break in the future if we implement more context and locale
5363 // dependent upper/lower conversions.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005364 Object* o;
5365 { MaybeObject* maybe_o = s->IsAsciiRepresentation()
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005366 ? isolate->heap()->AllocateRawAsciiString(length)
5367 : isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005368 if (!maybe_o->ToObject(&o)) return maybe_o;
5369 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005370 String* result = String::cast(o);
5371 bool has_changed_character = false;
5372
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005373 // Convert all characters to upper case, assuming that they will fit
5374 // in the buffer
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005375 Access<StringInputBuffer> buffer(
5376 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005377 buffer->Reset(s);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005378 unibrow::uchar chars[Converter::kMaxWidth];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005379 // We can assume that the string is not empty
5380 uc32 current = buffer->GetNext();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005381 for (int i = 0; i < length;) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00005382 bool has_next = buffer->has_more();
5383 uc32 next = has_next ? buffer->GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005384 int char_length = mapping->get(current, next, chars);
5385 if (char_length == 0) {
5386 // The case conversion of this character is the character itself.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005387 result->Set(i, current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005388 i++;
5389 } else if (char_length == 1) {
5390 // Common case: converting the letter resulted in one character.
5391 ASSERT(static_cast<uc32>(chars[0]) != current);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005392 result->Set(i, chars[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005393 has_changed_character = true;
5394 i++;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005395 } else if (length == input_string_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005396 // We've assumed that the result would be as long as the
5397 // input but here is a character that converts to several
5398 // characters. No matter, we calculate the exact length
5399 // of the result and try the whole thing again.
5400 //
5401 // Note that this leaves room for optimization. We could just
5402 // memcpy what we already have to the result string. Also,
5403 // the result string is the last object allocated we could
5404 // "realloc" it and probably, in the vast majority of cases,
5405 // extend the existing string to be able to hold the full
5406 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00005407 int next_length = 0;
5408 if (has_next) {
5409 next_length = mapping->get(next, 0, chars);
5410 if (next_length == 0) next_length = 1;
5411 }
5412 int current_length = i + char_length + next_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005413 while (buffer->has_more()) {
5414 current = buffer->GetNext();
ager@chromium.org7c537e22008-10-16 08:43:32 +00005415 // NOTE: we use 0 as the next character here because, while
5416 // the next character may affect what a character converts to,
5417 // it does not in any case affect the length of what it convert
5418 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005419 int char_length = mapping->get(current, 0, chars);
5420 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00005421 current_length += char_length;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005422 if (current_length > Smi::kMaxValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005423 isolate->context()->mark_out_of_memory();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005424 return Failure::OutOfMemoryException();
5425 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005426 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005427 // Try again with the real length.
5428 return Smi::FromInt(current_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005429 } else {
5430 for (int j = 0; j < char_length; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005431 result->Set(i, chars[j]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005432 i++;
5433 }
5434 has_changed_character = true;
5435 }
5436 current = next;
5437 }
5438 if (has_changed_character) {
5439 return result;
5440 } else {
5441 // If we didn't actually change anything in doing the conversion
5442 // we simple return the result and let the converted string
5443 // become garbage; there is no reason to keep two identical strings
5444 // alive.
5445 return s;
5446 }
5447}
5448
5449
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005450namespace {
5451
lrn@chromium.org303ada72010-10-27 09:33:13 +00005452static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF;
5453
5454
5455// Given a word and two range boundaries returns a word with high bit
5456// set in every byte iff the corresponding input byte was strictly in
5457// the range (m, n). All the other bits in the result are cleared.
5458// This function is only useful when it can be inlined and the
5459// boundaries are statically known.
5460// Requires: all bytes in the input word and the boundaries must be
5461// ascii (less than 0x7F).
5462static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
5463 // Every byte in an ascii string is less than or equal to 0x7F.
5464 ASSERT((w & (kOneInEveryByte * 0x7F)) == w);
5465 // Use strict inequalities since in edge cases the function could be
5466 // further simplified.
5467 ASSERT(0 < m && m < n && n < 0x7F);
5468 // Has high bit set in every w byte less than n.
5469 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w;
5470 // Has high bit set in every w byte greater than m.
5471 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m);
5472 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80));
5473}
5474
5475
5476enum AsciiCaseConversion {
5477 ASCII_TO_LOWER,
5478 ASCII_TO_UPPER
5479};
5480
5481
5482template <AsciiCaseConversion dir>
5483struct FastAsciiConverter {
5484 static bool Convert(char* dst, char* src, int length) {
5485#ifdef DEBUG
5486 char* saved_dst = dst;
5487 char* saved_src = src;
5488#endif
5489 // We rely on the distance between upper and lower case letters
5490 // being a known power of 2.
5491 ASSERT('a' - 'A' == (1 << 5));
5492 // Boundaries for the range of input characters than require conversion.
5493 const char lo = (dir == ASCII_TO_LOWER) ? 'A' - 1 : 'a' - 1;
5494 const char hi = (dir == ASCII_TO_LOWER) ? 'Z' + 1 : 'z' + 1;
5495 bool changed = false;
5496 char* const limit = src + length;
5497#ifdef V8_HOST_CAN_READ_UNALIGNED
5498 // Process the prefix of the input that requires no conversion one
5499 // (machine) word at a time.
5500 while (src <= limit - sizeof(uintptr_t)) {
5501 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
5502 if (AsciiRangeMask(w, lo, hi) != 0) {
5503 changed = true;
5504 break;
5505 }
5506 *reinterpret_cast<uintptr_t*>(dst) = w;
5507 src += sizeof(uintptr_t);
5508 dst += sizeof(uintptr_t);
5509 }
5510 // Process the remainder of the input performing conversion when
5511 // required one word at a time.
5512 while (src <= limit - sizeof(uintptr_t)) {
5513 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
5514 uintptr_t m = AsciiRangeMask(w, lo, hi);
5515 // The mask has high (7th) bit set in every byte that needs
5516 // conversion and we know that the distance between cases is
5517 // 1 << 5.
5518 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
5519 src += sizeof(uintptr_t);
5520 dst += sizeof(uintptr_t);
5521 }
5522#endif
5523 // Process the last few bytes of the input (or the whole input if
5524 // unaligned access is not supported).
5525 while (src < limit) {
5526 char c = *src;
5527 if (lo < c && c < hi) {
5528 c ^= (1 << 5);
5529 changed = true;
5530 }
5531 *dst = c;
5532 ++src;
5533 ++dst;
5534 }
5535#ifdef DEBUG
5536 CheckConvert(saved_dst, saved_src, length, changed);
5537#endif
5538 return changed;
5539 }
5540
5541#ifdef DEBUG
5542 static void CheckConvert(char* dst, char* src, int length, bool changed) {
5543 bool expected_changed = false;
5544 for (int i = 0; i < length; i++) {
5545 if (dst[i] == src[i]) continue;
5546 expected_changed = true;
5547 if (dir == ASCII_TO_LOWER) {
5548 ASSERT('A' <= src[i] && src[i] <= 'Z');
5549 ASSERT(dst[i] == src[i] + ('a' - 'A'));
5550 } else {
5551 ASSERT(dir == ASCII_TO_UPPER);
5552 ASSERT('a' <= src[i] && src[i] <= 'z');
5553 ASSERT(dst[i] == src[i] - ('a' - 'A'));
5554 }
5555 }
5556 ASSERT(expected_changed == changed);
5557 }
5558#endif
5559};
5560
5561
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005562struct ToLowerTraits {
5563 typedef unibrow::ToLowercase UnibrowConverter;
5564
lrn@chromium.org303ada72010-10-27 09:33:13 +00005565 typedef FastAsciiConverter<ASCII_TO_LOWER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005566};
5567
5568
5569struct ToUpperTraits {
5570 typedef unibrow::ToUppercase UnibrowConverter;
5571
lrn@chromium.org303ada72010-10-27 09:33:13 +00005572 typedef FastAsciiConverter<ASCII_TO_UPPER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005573};
5574
5575} // namespace
5576
5577
5578template <typename ConvertTraits>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005579MUST_USE_RESULT static MaybeObject* ConvertCase(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005580 Arguments args,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005581 Isolate* isolate,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005582 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005583 NoHandleAllocation ha;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005584 CONVERT_CHECKED(String, s, args[0]);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005585 s = s->TryFlattenGetString();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005586
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005587 const int length = s->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005588 // Assume that the string is not empty; we need this assumption later
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005589 if (length == 0) return s;
5590
5591 // Simpler handling of ascii strings.
5592 //
5593 // NOTE: This assumes that the upper/lower case of an ascii
5594 // character is also ascii. This is currently the case, but it
5595 // might break in the future if we implement more context and locale
5596 // dependent upper/lower conversions.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005597 if (s->IsSeqAsciiString()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005598 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005599 { MaybeObject* maybe_o = isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005600 if (!maybe_o->ToObject(&o)) return maybe_o;
5601 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005602 SeqAsciiString* result = SeqAsciiString::cast(o);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005603 bool has_changed_character = ConvertTraits::AsciiConverter::Convert(
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005604 result->GetChars(), SeqAsciiString::cast(s)->GetChars(), length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005605 return has_changed_character ? result : s;
5606 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005607
lrn@chromium.org303ada72010-10-27 09:33:13 +00005608 Object* answer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005609 { MaybeObject* maybe_answer =
5610 ConvertCaseHelper(isolate, s, length, length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005611 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5612 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005613 if (answer->IsSmi()) {
5614 // Retry with correct length.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005615 { MaybeObject* maybe_answer =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005616 ConvertCaseHelper(isolate,
5617 s, Smi::cast(answer)->value(), length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005618 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5619 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005620 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00005621 return answer;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005622}
5623
5624
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005625RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToLowerCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005626 return ConvertCase<ToLowerTraits>(
5627 args, isolate, isolate->runtime_state()->to_lower_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005628}
5629
5630
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005631RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToUpperCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005632 return ConvertCase<ToUpperTraits>(
5633 args, isolate, isolate->runtime_state()->to_upper_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005634}
5635
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005636
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005637static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
5638 return unibrow::WhiteSpace::Is(c) || c == 0x200b;
5639}
5640
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005641
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005642RUNTIME_FUNCTION(MaybeObject*, Runtime_StringTrim) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005643 NoHandleAllocation ha;
5644 ASSERT(args.length() == 3);
5645
5646 CONVERT_CHECKED(String, s, args[0]);
5647 CONVERT_BOOLEAN_CHECKED(trimLeft, args[1]);
5648 CONVERT_BOOLEAN_CHECKED(trimRight, args[2]);
5649
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005650 s->TryFlatten();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005651 int length = s->length();
5652
5653 int left = 0;
5654 if (trimLeft) {
5655 while (left < length && IsTrimWhiteSpace(s->Get(left))) {
5656 left++;
5657 }
5658 }
5659
5660 int right = length;
5661 if (trimRight) {
5662 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) {
5663 right--;
5664 }
5665 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005666 return s->SubString(left, right);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005667}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005668
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005669
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005670template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005671void FindStringIndices(Isolate* isolate,
5672 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005673 Vector<const PatternChar> pattern,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005674 ZoneList<int>* indices,
5675 unsigned int limit) {
5676 ASSERT(limit > 0);
5677 // Collect indices of pattern in subject, and the end-of-string index.
5678 // Stop after finding at most limit values.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005679 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005680 int pattern_length = pattern.length();
5681 int index = 0;
5682 while (limit > 0) {
5683 index = search.Search(subject, index);
5684 if (index < 0) return;
5685 indices->Add(index);
5686 index += pattern_length;
5687 limit--;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005688 }
5689}
5690
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005691
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005692RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005693 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005694 HandleScope handle_scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005695 CONVERT_ARG_CHECKED(String, subject, 0);
5696 CONVERT_ARG_CHECKED(String, pattern, 1);
5697 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
5698
5699 int subject_length = subject->length();
5700 int pattern_length = pattern->length();
5701 RUNTIME_ASSERT(pattern_length > 0);
5702
5703 // The limit can be very large (0xffffffffu), but since the pattern
5704 // isn't empty, we can never create more parts than ~half the length
5705 // of the subject.
5706
5707 if (!subject->IsFlat()) FlattenString(subject);
5708
5709 static const int kMaxInitialListCapacity = 16;
5710
danno@chromium.org40cb8782011-05-25 07:58:50 +00005711 ZoneScope scope(isolate, DELETE_ON_EXIT);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005712
5713 // Find (up to limit) indices of separator and end-of-string in subject
5714 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
5715 ZoneList<int> indices(initial_capacity);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005716 if (!pattern->IsFlat()) FlattenString(pattern);
5717
5718 // No allocation block.
5719 {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005720 AssertNoAllocation nogc;
5721 if (subject->IsAsciiRepresentation()) {
5722 Vector<const char> subject_vector = subject->ToAsciiVector();
5723 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005724 FindStringIndices(isolate,
5725 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005726 pattern->ToAsciiVector(),
5727 &indices,
5728 limit);
5729 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005730 FindStringIndices(isolate,
5731 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005732 pattern->ToUC16Vector(),
5733 &indices,
5734 limit);
5735 }
5736 } else {
5737 Vector<const uc16> subject_vector = subject->ToUC16Vector();
5738 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005739 FindStringIndices(isolate,
5740 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005741 pattern->ToAsciiVector(),
5742 &indices,
5743 limit);
5744 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005745 FindStringIndices(isolate,
5746 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005747 pattern->ToUC16Vector(),
5748 &indices,
5749 limit);
5750 }
5751 }
5752 }
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005753
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005754 if (static_cast<uint32_t>(indices.length()) < limit) {
5755 indices.Add(subject_length);
5756 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005757
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005758 // The list indices now contains the end of each part to create.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005759
5760 // Create JSArray of substrings separated by separator.
5761 int part_count = indices.length();
5762
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005763 Handle<JSArray> result = isolate->factory()->NewJSArray(part_count);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005764 result->set_length(Smi::FromInt(part_count));
5765
5766 ASSERT(result->HasFastElements());
5767
5768 if (part_count == 1 && indices.at(0) == subject_length) {
5769 FixedArray::cast(result->elements())->set(0, *subject);
5770 return *result;
5771 }
5772
5773 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
5774 int part_start = 0;
5775 for (int i = 0; i < part_count; i++) {
5776 HandleScope local_loop_handle;
5777 int part_end = indices.at(i);
5778 Handle<String> substring =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005779 isolate->factory()->NewSubString(subject, part_start, part_end);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005780 elements->set(i, *substring);
5781 part_start = part_end + pattern_length;
5782 }
5783
5784 return *result;
5785}
5786
5787
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005788// Copies ascii characters to the given fixed array looking up
5789// one-char strings in the cache. Gives up on the first char that is
5790// not in the cache and fills the remainder with smi zeros. Returns
5791// the length of the successfully copied prefix.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005792static int CopyCachedAsciiCharsToArray(Heap* heap,
5793 const char* chars,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005794 FixedArray* elements,
5795 int length) {
5796 AssertNoAllocation nogc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005797 FixedArray* ascii_cache = heap->single_character_string_cache();
5798 Object* undefined = heap->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005799 int i;
5800 for (i = 0; i < length; ++i) {
5801 Object* value = ascii_cache->get(chars[i]);
5802 if (value == undefined) break;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005803 ASSERT(!heap->InNewSpace(value));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005804 elements->set(i, value, SKIP_WRITE_BARRIER);
5805 }
5806 if (i < length) {
5807 ASSERT(Smi::FromInt(0) == 0);
5808 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
5809 }
5810#ifdef DEBUG
5811 for (int j = 0; j < length; ++j) {
5812 Object* element = elements->get(j);
5813 ASSERT(element == Smi::FromInt(0) ||
5814 (element->IsString() && String::cast(element)->LooksValid()));
5815 }
5816#endif
5817 return i;
5818}
5819
5820
5821// Converts a String to JSArray.
5822// For example, "foo" => ["f", "o", "o"].
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005823RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToArray) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005824 HandleScope scope(isolate);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005825 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005826 CONVERT_ARG_CHECKED(String, s, 0);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005827 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005828
5829 s->TryFlatten();
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005830 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005831
5832 Handle<FixedArray> elements;
5833 if (s->IsFlat() && s->IsAsciiRepresentation()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005834 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005835 { MaybeObject* maybe_obj =
5836 isolate->heap()->AllocateUninitializedFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005837 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5838 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005839 elements = Handle<FixedArray>(FixedArray::cast(obj), isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005840
5841 Vector<const char> chars = s->ToAsciiVector();
5842 // Note, this will initialize all elements (not only the prefix)
5843 // to prevent GC from seeing partially initialized array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005844 int num_copied_from_cache = CopyCachedAsciiCharsToArray(isolate->heap(),
5845 chars.start(),
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005846 *elements,
5847 length);
5848
5849 for (int i = num_copied_from_cache; i < length; ++i) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00005850 Handle<Object> str = LookupSingleCharacterStringFromCode(chars[i]);
5851 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005852 }
5853 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005854 elements = isolate->factory()->NewFixedArray(length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005855 for (int i = 0; i < length; ++i) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00005856 Handle<Object> str = LookupSingleCharacterStringFromCode(s->Get(i));
5857 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005858 }
5859 }
5860
5861#ifdef DEBUG
5862 for (int i = 0; i < length; ++i) {
5863 ASSERT(String::cast(elements->get(i))->length() == 1);
5864 }
5865#endif
5866
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005867 return *isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005868}
5869
5870
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005871RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStringWrapper) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005872 NoHandleAllocation ha;
5873 ASSERT(args.length() == 1);
5874 CONVERT_CHECKED(String, value, args[0]);
5875 return value->ToObject();
5876}
5877
5878
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005879bool Runtime::IsUpperCaseChar(RuntimeState* runtime_state, uint16_t ch) {
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00005880 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005881 int char_length = runtime_state->to_upper_mapping()->get(ch, 0, chars);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00005882 return char_length == 0;
5883}
5884
5885
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005886RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005887 NoHandleAllocation ha;
5888 ASSERT(args.length() == 1);
5889
5890 Object* number = args[0];
5891 RUNTIME_ASSERT(number->IsNumber());
5892
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005893 return isolate->heap()->NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005894}
5895
5896
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005897RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToStringSkipCache) {
ager@chromium.org357bf652010-04-12 11:30:10 +00005898 NoHandleAllocation ha;
5899 ASSERT(args.length() == 1);
5900
5901 Object* number = args[0];
5902 RUNTIME_ASSERT(number->IsNumber());
5903
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005904 return isolate->heap()->NumberToString(number, false);
ager@chromium.org357bf652010-04-12 11:30:10 +00005905}
5906
5907
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005908RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToInteger) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005909 NoHandleAllocation ha;
5910 ASSERT(args.length() == 1);
5911
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005912 CONVERT_DOUBLE_CHECKED(number, args[0]);
5913
5914 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5915 if (number > 0 && number <= Smi::kMaxValue) {
5916 return Smi::FromInt(static_cast<int>(number));
5917 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005918 return isolate->heap()->NumberFromDouble(DoubleToInteger(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005919}
5920
5921
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005922RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToIntegerMapMinusZero) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005923 NoHandleAllocation ha;
5924 ASSERT(args.length() == 1);
5925
5926 CONVERT_DOUBLE_CHECKED(number, args[0]);
5927
5928 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5929 if (number > 0 && number <= Smi::kMaxValue) {
5930 return Smi::FromInt(static_cast<int>(number));
5931 }
5932
5933 double double_value = DoubleToInteger(number);
5934 // Map both -0 and +0 to +0.
5935 if (double_value == 0) double_value = 0;
5936
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005937 return isolate->heap()->NumberFromDouble(double_value);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005938}
5939
5940
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005941RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSUint32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005942 NoHandleAllocation ha;
5943 ASSERT(args.length() == 1);
5944
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005945 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005946 return isolate->heap()->NumberFromUint32(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005947}
5948
5949
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005950RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSInt32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005951 NoHandleAllocation ha;
5952 ASSERT(args.length() == 1);
5953
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005954 CONVERT_DOUBLE_CHECKED(number, args[0]);
5955
5956 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5957 if (number > 0 && number <= Smi::kMaxValue) {
5958 return Smi::FromInt(static_cast<int>(number));
5959 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005960 return isolate->heap()->NumberFromInt32(DoubleToInt32(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005961}
5962
5963
ager@chromium.org870a0b62008-11-04 11:43:05 +00005964// Converts a Number to a Smi, if possible. Returns NaN if the number is not
5965// a small integer.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005966RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToSmi) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00005967 NoHandleAllocation ha;
5968 ASSERT(args.length() == 1);
5969
5970 Object* obj = args[0];
5971 if (obj->IsSmi()) {
5972 return obj;
5973 }
5974 if (obj->IsHeapNumber()) {
5975 double value = HeapNumber::cast(obj)->value();
5976 int int_value = FastD2I(value);
5977 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
5978 return Smi::FromInt(int_value);
5979 }
5980 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005981 return isolate->heap()->nan_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00005982}
5983
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005984
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005985RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateHeapNumber) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005986 NoHandleAllocation ha;
5987 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005988 return isolate->heap()->AllocateHeapNumber(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005989}
5990
5991
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005992RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005993 NoHandleAllocation ha;
5994 ASSERT(args.length() == 2);
5995
5996 CONVERT_DOUBLE_CHECKED(x, args[0]);
5997 CONVERT_DOUBLE_CHECKED(y, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005998 return isolate->heap()->NumberFromDouble(x + y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005999}
6000
6001
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006002RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSub) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006003 NoHandleAllocation ha;
6004 ASSERT(args.length() == 2);
6005
6006 CONVERT_DOUBLE_CHECKED(x, args[0]);
6007 CONVERT_DOUBLE_CHECKED(y, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006008 return isolate->heap()->NumberFromDouble(x - y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006009}
6010
6011
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006012RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMul) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006013 NoHandleAllocation ha;
6014 ASSERT(args.length() == 2);
6015
6016 CONVERT_DOUBLE_CHECKED(x, args[0]);
6017 CONVERT_DOUBLE_CHECKED(y, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006018 return isolate->heap()->NumberFromDouble(x * y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006019}
6020
6021
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006022RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberUnaryMinus) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006023 NoHandleAllocation ha;
6024 ASSERT(args.length() == 1);
6025
6026 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006027 return isolate->heap()->NumberFromDouble(-x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006028}
6029
6030
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006031RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAlloc) {
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006032 NoHandleAllocation ha;
6033 ASSERT(args.length() == 0);
6034
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006035 return isolate->heap()->NumberFromDouble(9876543210.0);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006036}
6037
6038
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006039RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberDiv) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006040 NoHandleAllocation ha;
6041 ASSERT(args.length() == 2);
6042
6043 CONVERT_DOUBLE_CHECKED(x, args[0]);
6044 CONVERT_DOUBLE_CHECKED(y, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006045 return isolate->heap()->NumberFromDouble(x / y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006046}
6047
6048
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006049RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMod) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006050 NoHandleAllocation ha;
6051 ASSERT(args.length() == 2);
6052
6053 CONVERT_DOUBLE_CHECKED(x, args[0]);
6054 CONVERT_DOUBLE_CHECKED(y, args[1]);
6055
ager@chromium.org3811b432009-10-28 14:53:37 +00006056 x = modulo(x, y);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006057 // NumberFromDouble may return a Smi instead of a Number object
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006058 return isolate->heap()->NumberFromDouble(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006059}
6060
6061
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006062RUNTIME_FUNCTION(MaybeObject*, Runtime_StringAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006063 NoHandleAllocation ha;
6064 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006065 CONVERT_CHECKED(String, str1, args[0]);
6066 CONVERT_CHECKED(String, str2, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006067 isolate->counters()->string_add_runtime()->Increment();
6068 return isolate->heap()->AllocateConsString(str1, str2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006069}
6070
6071
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006072template <typename sinkchar>
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006073static inline void StringBuilderConcatHelper(String* special,
6074 sinkchar* sink,
6075 FixedArray* fixed_array,
6076 int array_length) {
6077 int position = 0;
6078 for (int i = 0; i < array_length; i++) {
6079 Object* element = fixed_array->get(i);
6080 if (element->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006081 // Smi encoding of position and length.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006082 int encoded_slice = Smi::cast(element)->value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006083 int pos;
6084 int len;
6085 if (encoded_slice > 0) {
6086 // Position and length encoded in one smi.
6087 pos = StringBuilderSubstringPosition::decode(encoded_slice);
6088 len = StringBuilderSubstringLength::decode(encoded_slice);
6089 } else {
6090 // Position and length encoded in two smis.
6091 Object* obj = fixed_array->get(++i);
6092 ASSERT(obj->IsSmi());
6093 pos = Smi::cast(obj)->value();
6094 len = -encoded_slice;
6095 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00006096 String::WriteToFlat(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00006097 sink + position,
6098 pos,
6099 pos + len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006100 position += len;
6101 } else {
6102 String* string = String::cast(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006103 int element_length = string->length();
6104 String::WriteToFlat(string, sink + position, 0, element_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006105 position += element_length;
6106 }
6107 }
6108}
6109
6110
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006111RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006112 NoHandleAllocation ha;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006113 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006114 CONVERT_CHECKED(JSArray, array, args[0]);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006115 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006116 isolate->context()->mark_out_of_memory();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006117 return Failure::OutOfMemoryException();
6118 }
6119 int array_length = Smi::cast(args[1])->value();
6120 CONVERT_CHECKED(String, special, args[2]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006121
6122 // This assumption is used by the slice encoding in one or two smis.
6123 ASSERT(Smi::kMaxValue >= String::kMaxLength);
6124
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006125 int special_length = special->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006126 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006127 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006128 }
6129 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006130 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006131 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006132 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006133
6134 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006135 return isolate->heap()->empty_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006136 } else if (array_length == 1) {
6137 Object* first = fixed_array->get(0);
6138 if (first->IsString()) return first;
6139 }
6140
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006141 bool ascii = special->HasOnlyAsciiChars();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006142 int position = 0;
6143 for (int i = 0; i < array_length; i++) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006144 int increment = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006145 Object* elt = fixed_array->get(i);
6146 if (elt->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006147 // Smi encoding of position and length.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006148 int smi_value = Smi::cast(elt)->value();
6149 int pos;
6150 int len;
6151 if (smi_value > 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006152 // Position and length encoded in one smi.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006153 pos = StringBuilderSubstringPosition::decode(smi_value);
6154 len = StringBuilderSubstringLength::decode(smi_value);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006155 } else {
6156 // Position and length encoded in two smis.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006157 len = -smi_value;
6158 // Get the position and check that it is a positive smi.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006159 i++;
6160 if (i >= array_length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006161 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006162 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006163 Object* next_smi = fixed_array->get(i);
6164 if (!next_smi->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006165 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006166 }
6167 pos = Smi::cast(next_smi)->value();
6168 if (pos < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006169 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006170 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006171 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006172 ASSERT(pos >= 0);
6173 ASSERT(len >= 0);
6174 if (pos > special_length || len > special_length - pos) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006175 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006176 }
6177 increment = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006178 } else if (elt->IsString()) {
6179 String* element = String::cast(elt);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006180 int element_length = element->length();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006181 increment = element_length;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006182 if (ascii && !element->HasOnlyAsciiChars()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006183 ascii = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006184 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006185 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006186 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006187 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006188 if (increment > String::kMaxLength - position) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006189 isolate->context()->mark_out_of_memory();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006190 return Failure::OutOfMemoryException();
6191 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006192 position += increment;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006193 }
6194
6195 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006196 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006197
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006198 if (ascii) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006199 { MaybeObject* maybe_object =
6200 isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006201 if (!maybe_object->ToObject(&object)) return maybe_object;
6202 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006203 SeqAsciiString* answer = SeqAsciiString::cast(object);
6204 StringBuilderConcatHelper(special,
6205 answer->GetChars(),
6206 fixed_array,
6207 array_length);
6208 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006209 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006210 { MaybeObject* maybe_object =
6211 isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006212 if (!maybe_object->ToObject(&object)) return maybe_object;
6213 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006214 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6215 StringBuilderConcatHelper(special,
6216 answer->GetChars(),
6217 fixed_array,
6218 array_length);
6219 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006220 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006221}
6222
6223
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006224RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderJoin) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006225 NoHandleAllocation ha;
6226 ASSERT(args.length() == 3);
6227 CONVERT_CHECKED(JSArray, array, args[0]);
6228 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006229 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006230 return Failure::OutOfMemoryException();
6231 }
6232 int array_length = Smi::cast(args[1])->value();
6233 CONVERT_CHECKED(String, separator, args[2]);
6234
6235 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006236 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006237 }
6238 FixedArray* fixed_array = FixedArray::cast(array->elements());
6239 if (fixed_array->length() < array_length) {
6240 array_length = fixed_array->length();
6241 }
6242
6243 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006244 return isolate->heap()->empty_string();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006245 } else if (array_length == 1) {
6246 Object* first = fixed_array->get(0);
6247 if (first->IsString()) return first;
6248 }
6249
6250 int separator_length = separator->length();
6251 int max_nof_separators =
6252 (String::kMaxLength + separator_length - 1) / separator_length;
6253 if (max_nof_separators < (array_length - 1)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006254 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006255 return Failure::OutOfMemoryException();
6256 }
6257 int length = (array_length - 1) * separator_length;
6258 for (int i = 0; i < array_length; i++) {
6259 Object* element_obj = fixed_array->get(i);
6260 if (!element_obj->IsString()) {
6261 // TODO(1161): handle this case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006262 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006263 }
6264 String* element = String::cast(element_obj);
6265 int increment = element->length();
6266 if (increment > String::kMaxLength - length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006267 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006268 return Failure::OutOfMemoryException();
6269 }
6270 length += increment;
6271 }
6272
6273 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006274 { MaybeObject* maybe_object =
6275 isolate->heap()->AllocateRawTwoByteString(length);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006276 if (!maybe_object->ToObject(&object)) return maybe_object;
6277 }
6278 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6279
6280 uc16* sink = answer->GetChars();
6281#ifdef DEBUG
6282 uc16* end = sink + length;
6283#endif
6284
6285 String* first = String::cast(fixed_array->get(0));
6286 int first_length = first->length();
6287 String::WriteToFlat(first, sink, 0, first_length);
6288 sink += first_length;
6289
6290 for (int i = 1; i < array_length; i++) {
6291 ASSERT(sink + separator_length <= end);
6292 String::WriteToFlat(separator, sink, 0, separator_length);
6293 sink += separator_length;
6294
6295 String* element = String::cast(fixed_array->get(i));
6296 int element_length = element->length();
6297 ASSERT(sink + element_length <= end);
6298 String::WriteToFlat(element, sink, 0, element_length);
6299 sink += element_length;
6300 }
6301 ASSERT(sink == end);
6302
6303 ASSERT(!answer->HasOnlyAsciiChars()); // Use %_FastAsciiArrayJoin instead.
6304 return answer;
6305}
6306
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006307template <typename Char>
6308static void JoinSparseArrayWithSeparator(FixedArray* elements,
6309 int elements_length,
6310 uint32_t array_length,
6311 String* separator,
6312 Vector<Char> buffer) {
6313 int previous_separator_position = 0;
6314 int separator_length = separator->length();
6315 int cursor = 0;
6316 for (int i = 0; i < elements_length; i += 2) {
6317 int position = NumberToInt32(elements->get(i));
6318 String* string = String::cast(elements->get(i + 1));
6319 int string_length = string->length();
6320 if (string->length() > 0) {
6321 while (previous_separator_position < position) {
6322 String::WriteToFlat<Char>(separator, &buffer[cursor],
6323 0, separator_length);
6324 cursor += separator_length;
6325 previous_separator_position++;
6326 }
6327 String::WriteToFlat<Char>(string, &buffer[cursor],
6328 0, string_length);
6329 cursor += string->length();
6330 }
6331 }
6332 if (separator_length > 0) {
6333 // Array length must be representable as a signed 32-bit number,
6334 // otherwise the total string length would have been too large.
6335 ASSERT(array_length <= 0x7fffffff); // Is int32_t.
6336 int last_array_index = static_cast<int>(array_length - 1);
6337 while (previous_separator_position < last_array_index) {
6338 String::WriteToFlat<Char>(separator, &buffer[cursor],
6339 0, separator_length);
6340 cursor += separator_length;
6341 previous_separator_position++;
6342 }
6343 }
6344 ASSERT(cursor <= buffer.length());
6345}
6346
6347
6348RUNTIME_FUNCTION(MaybeObject*, Runtime_SparseJoinWithSeparator) {
6349 NoHandleAllocation ha;
6350 ASSERT(args.length() == 3);
6351 CONVERT_CHECKED(JSArray, elements_array, args[0]);
6352 RUNTIME_ASSERT(elements_array->HasFastElements());
6353 CONVERT_NUMBER_CHECKED(uint32_t, array_length, Uint32, args[1]);
6354 CONVERT_CHECKED(String, separator, args[2]);
6355 // elements_array is fast-mode JSarray of alternating positions
6356 // (increasing order) and strings.
6357 // array_length is length of original array (used to add separators);
6358 // separator is string to put between elements. Assumed to be non-empty.
6359
6360 // Find total length of join result.
6361 int string_length = 0;
6362 bool is_ascii = true;
6363 int max_string_length = SeqAsciiString::kMaxLength;
6364 bool overflow = false;
6365 CONVERT_NUMBER_CHECKED(int, elements_length,
6366 Int32, elements_array->length());
6367 RUNTIME_ASSERT((elements_length & 1) == 0); // Even length.
6368 FixedArray* elements = FixedArray::cast(elements_array->elements());
6369 for (int i = 0; i < elements_length; i += 2) {
6370 RUNTIME_ASSERT(elements->get(i)->IsNumber());
6371 CONVERT_CHECKED(String, string, elements->get(i + 1));
6372 int length = string->length();
6373 if (is_ascii && !string->IsAsciiRepresentation()) {
6374 is_ascii = false;
6375 max_string_length = SeqTwoByteString::kMaxLength;
6376 }
6377 if (length > max_string_length ||
6378 max_string_length - length < string_length) {
6379 overflow = true;
6380 break;
6381 }
6382 string_length += length;
6383 }
6384 int separator_length = separator->length();
6385 if (!overflow && separator_length > 0) {
6386 if (array_length <= 0x7fffffffu) {
6387 int separator_count = static_cast<int>(array_length) - 1;
6388 int remaining_length = max_string_length - string_length;
6389 if ((remaining_length / separator_length) >= separator_count) {
6390 string_length += separator_length * (array_length - 1);
6391 } else {
6392 // Not room for the separators within the maximal string length.
6393 overflow = true;
6394 }
6395 } else {
6396 // Nonempty separator and at least 2^31-1 separators necessary
6397 // means that the string is too large to create.
6398 STATIC_ASSERT(String::kMaxLength < 0x7fffffff);
6399 overflow = true;
6400 }
6401 }
6402 if (overflow) {
6403 // Throw OutOfMemory exception for creating too large a string.
6404 V8::FatalProcessOutOfMemory("Array join result too large.");
6405 }
6406
6407 if (is_ascii) {
6408 MaybeObject* result_allocation =
6409 isolate->heap()->AllocateRawAsciiString(string_length);
6410 if (result_allocation->IsFailure()) return result_allocation;
6411 SeqAsciiString* result_string =
6412 SeqAsciiString::cast(result_allocation->ToObjectUnchecked());
6413 JoinSparseArrayWithSeparator<char>(elements,
6414 elements_length,
6415 array_length,
6416 separator,
6417 Vector<char>(result_string->GetChars(),
6418 string_length));
6419 return result_string;
6420 } else {
6421 MaybeObject* result_allocation =
6422 isolate->heap()->AllocateRawTwoByteString(string_length);
6423 if (result_allocation->IsFailure()) return result_allocation;
6424 SeqTwoByteString* result_string =
6425 SeqTwoByteString::cast(result_allocation->ToObjectUnchecked());
6426 JoinSparseArrayWithSeparator<uc16>(elements,
6427 elements_length,
6428 array_length,
6429 separator,
6430 Vector<uc16>(result_string->GetChars(),
6431 string_length));
6432 return result_string;
6433 }
6434}
6435
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006436
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006437RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberOr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006438 NoHandleAllocation ha;
6439 ASSERT(args.length() == 2);
6440
6441 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6442 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006443 return isolate->heap()->NumberFromInt32(x | y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006444}
6445
6446
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006447RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAnd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006448 NoHandleAllocation ha;
6449 ASSERT(args.length() == 2);
6450
6451 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6452 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006453 return isolate->heap()->NumberFromInt32(x & y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006454}
6455
6456
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006457RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberXor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006458 NoHandleAllocation ha;
6459 ASSERT(args.length() == 2);
6460
6461 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6462 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006463 return isolate->heap()->NumberFromInt32(x ^ y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006464}
6465
6466
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006467RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberNot) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006468 NoHandleAllocation ha;
6469 ASSERT(args.length() == 1);
6470
6471 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006472 return isolate->heap()->NumberFromInt32(~x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006473}
6474
6475
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006476RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShl) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006477 NoHandleAllocation ha;
6478 ASSERT(args.length() == 2);
6479
6480 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6481 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006482 return isolate->heap()->NumberFromInt32(x << (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006483}
6484
6485
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006486RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006487 NoHandleAllocation ha;
6488 ASSERT(args.length() == 2);
6489
6490 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
6491 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006492 return isolate->heap()->NumberFromUint32(x >> (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006493}
6494
6495
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006496RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSar) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006497 NoHandleAllocation ha;
6498 ASSERT(args.length() == 2);
6499
6500 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6501 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006502 return isolate->heap()->NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006503}
6504
6505
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006506RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006507 NoHandleAllocation ha;
6508 ASSERT(args.length() == 2);
6509
6510 CONVERT_DOUBLE_CHECKED(x, args[0]);
6511 CONVERT_DOUBLE_CHECKED(y, args[1]);
6512 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
6513 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
6514 if (x == y) return Smi::FromInt(EQUAL);
6515 Object* result;
6516 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
6517 result = Smi::FromInt(EQUAL);
6518 } else {
6519 result = Smi::FromInt(NOT_EQUAL);
6520 }
6521 return result;
6522}
6523
6524
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006525RUNTIME_FUNCTION(MaybeObject*, Runtime_StringEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006526 NoHandleAllocation ha;
6527 ASSERT(args.length() == 2);
6528
6529 CONVERT_CHECKED(String, x, args[0]);
6530 CONVERT_CHECKED(String, y, args[1]);
6531
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006532 bool not_equal = !x->Equals(y);
6533 // This is slightly convoluted because the value that signifies
6534 // equality is 0 and inequality is 1 so we have to negate the result
6535 // from String::Equals.
6536 ASSERT(not_equal == 0 || not_equal == 1);
6537 STATIC_CHECK(EQUAL == 0);
6538 STATIC_CHECK(NOT_EQUAL == 1);
6539 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006540}
6541
6542
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006543RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006544 NoHandleAllocation ha;
6545 ASSERT(args.length() == 3);
6546
6547 CONVERT_DOUBLE_CHECKED(x, args[0]);
6548 CONVERT_DOUBLE_CHECKED(y, args[1]);
6549 if (isnan(x) || isnan(y)) return args[2];
6550 if (x == y) return Smi::FromInt(EQUAL);
6551 if (isless(x, y)) return Smi::FromInt(LESS);
6552 return Smi::FromInt(GREATER);
6553}
6554
6555
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006556// Compare two Smis as if they were converted to strings and then
6557// compared lexicographically.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006558RUNTIME_FUNCTION(MaybeObject*, Runtime_SmiLexicographicCompare) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006559 NoHandleAllocation ha;
6560 ASSERT(args.length() == 2);
6561
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006562 // Extract the integer values from the Smis.
6563 CONVERT_CHECKED(Smi, x, args[0]);
6564 CONVERT_CHECKED(Smi, y, args[1]);
6565 int x_value = x->value();
6566 int y_value = y->value();
6567
6568 // If the integers are equal so are the string representations.
6569 if (x_value == y_value) return Smi::FromInt(EQUAL);
6570
6571 // If one of the integers are zero the normal integer order is the
6572 // same as the lexicographic order of the string representations.
6573 if (x_value == 0 || y_value == 0) return Smi::FromInt(x_value - y_value);
6574
ager@chromium.org32912102009-01-16 10:38:43 +00006575 // If only one of the integers is negative the negative number is
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006576 // smallest because the char code of '-' is less than the char code
6577 // of any digit. Otherwise, we make both values positive.
6578 if (x_value < 0 || y_value < 0) {
6579 if (y_value >= 0) return Smi::FromInt(LESS);
6580 if (x_value >= 0) return Smi::FromInt(GREATER);
6581 x_value = -x_value;
6582 y_value = -y_value;
6583 }
6584
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006585 // Arrays for the individual characters of the two Smis. Smis are
6586 // 31 bit integers and 10 decimal digits are therefore enough.
6587 // TODO(isolates): maybe we should simply allocate 20 bytes on the stack.
6588 int* x_elms = isolate->runtime_state()->smi_lexicographic_compare_x_elms();
6589 int* y_elms = isolate->runtime_state()->smi_lexicographic_compare_y_elms();
6590
6591
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006592 // Convert the integers to arrays of their decimal digits.
6593 int x_index = 0;
6594 int y_index = 0;
6595 while (x_value > 0) {
6596 x_elms[x_index++] = x_value % 10;
6597 x_value /= 10;
6598 }
6599 while (y_value > 0) {
6600 y_elms[y_index++] = y_value % 10;
6601 y_value /= 10;
6602 }
6603
6604 // Loop through the arrays of decimal digits finding the first place
6605 // where they differ.
6606 while (--x_index >= 0 && --y_index >= 0) {
6607 int diff = x_elms[x_index] - y_elms[y_index];
6608 if (diff != 0) return Smi::FromInt(diff);
6609 }
6610
6611 // If one array is a suffix of the other array, the longest array is
6612 // the representation of the largest of the Smis in the
6613 // lexicographic ordering.
6614 return Smi::FromInt(x_index - y_index);
6615}
6616
6617
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006618static Object* StringInputBufferCompare(RuntimeState* state,
6619 String* x,
6620 String* y) {
6621 StringInputBuffer& bufx = *state->string_input_buffer_compare_bufx();
6622 StringInputBuffer& bufy = *state->string_input_buffer_compare_bufy();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006623 bufx.Reset(x);
6624 bufy.Reset(y);
6625 while (bufx.has_more() && bufy.has_more()) {
6626 int d = bufx.GetNext() - bufy.GetNext();
6627 if (d < 0) return Smi::FromInt(LESS);
6628 else if (d > 0) return Smi::FromInt(GREATER);
6629 }
6630
6631 // x is (non-trivial) prefix of y:
6632 if (bufy.has_more()) return Smi::FromInt(LESS);
6633 // y is prefix of x:
6634 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
6635}
6636
6637
6638static Object* FlatStringCompare(String* x, String* y) {
6639 ASSERT(x->IsFlat());
6640 ASSERT(y->IsFlat());
6641 Object* equal_prefix_result = Smi::FromInt(EQUAL);
6642 int prefix_length = x->length();
6643 if (y->length() < prefix_length) {
6644 prefix_length = y->length();
6645 equal_prefix_result = Smi::FromInt(GREATER);
6646 } else if (y->length() > prefix_length) {
6647 equal_prefix_result = Smi::FromInt(LESS);
6648 }
6649 int r;
6650 if (x->IsAsciiRepresentation()) {
6651 Vector<const char> x_chars = x->ToAsciiVector();
6652 if (y->IsAsciiRepresentation()) {
6653 Vector<const char> y_chars = y->ToAsciiVector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006654 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006655 } else {
6656 Vector<const uc16> y_chars = y->ToUC16Vector();
6657 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6658 }
6659 } else {
6660 Vector<const uc16> x_chars = x->ToUC16Vector();
6661 if (y->IsAsciiRepresentation()) {
6662 Vector<const char> y_chars = y->ToAsciiVector();
6663 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6664 } else {
6665 Vector<const uc16> y_chars = y->ToUC16Vector();
6666 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6667 }
6668 }
6669 Object* result;
6670 if (r == 0) {
6671 result = equal_prefix_result;
6672 } else {
6673 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
6674 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006675 ASSERT(result ==
6676 StringInputBufferCompare(Isolate::Current()->runtime_state(), x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006677 return result;
6678}
6679
6680
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006681RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006682 NoHandleAllocation ha;
6683 ASSERT(args.length() == 2);
6684
6685 CONVERT_CHECKED(String, x, args[0]);
6686 CONVERT_CHECKED(String, y, args[1]);
6687
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006688 isolate->counters()->string_compare_runtime()->Increment();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006689
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006690 // A few fast case tests before we flatten.
6691 if (x == y) return Smi::FromInt(EQUAL);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006692 if (y->length() == 0) {
6693 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006694 return Smi::FromInt(GREATER);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006695 } else if (x->length() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006696 return Smi::FromInt(LESS);
6697 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006698
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006699 int d = x->Get(0) - y->Get(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006700 if (d < 0) return Smi::FromInt(LESS);
6701 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006702
lrn@chromium.org303ada72010-10-27 09:33:13 +00006703 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006704 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(x);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006705 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6706 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006707 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(y);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006708 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6709 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006710
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006711 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006712 : StringInputBufferCompare(isolate->runtime_state(), x, y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006713}
6714
6715
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006716RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_acos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006717 NoHandleAllocation ha;
6718 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006719 isolate->counters()->math_acos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006720
6721 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006722 return isolate->transcendental_cache()->Get(TranscendentalCache::ACOS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006723}
6724
6725
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006726RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_asin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006727 NoHandleAllocation ha;
6728 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006729 isolate->counters()->math_asin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006730
6731 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006732 return isolate->transcendental_cache()->Get(TranscendentalCache::ASIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006733}
6734
6735
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006736RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006737 NoHandleAllocation ha;
6738 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006739 isolate->counters()->math_atan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006740
6741 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006742 return isolate->transcendental_cache()->Get(TranscendentalCache::ATAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006743}
6744
6745
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006746static const double kPiDividedBy4 = 0.78539816339744830962;
6747
6748
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006749RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan2) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006750 NoHandleAllocation ha;
6751 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006752 isolate->counters()->math_atan2()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006753
6754 CONVERT_DOUBLE_CHECKED(x, args[0]);
6755 CONVERT_DOUBLE_CHECKED(y, args[1]);
6756 double result;
6757 if (isinf(x) && isinf(y)) {
6758 // Make sure that the result in case of two infinite arguments
6759 // is a multiple of Pi / 4. The sign of the result is determined
6760 // by the first argument (x) and the sign of the second argument
6761 // determines the multiplier: one or three.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006762 int multiplier = (x < 0) ? -1 : 1;
6763 if (y < 0) multiplier *= 3;
6764 result = multiplier * kPiDividedBy4;
6765 } else {
6766 result = atan2(x, y);
6767 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006768 return isolate->heap()->AllocateHeapNumber(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006769}
6770
6771
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006772RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_ceil) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006773 NoHandleAllocation ha;
6774 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006775 isolate->counters()->math_ceil()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006776
6777 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006778 return isolate->heap()->NumberFromDouble(ceiling(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006779}
6780
6781
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006782RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_cos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006783 NoHandleAllocation ha;
6784 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006785 isolate->counters()->math_cos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006786
6787 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006788 return isolate->transcendental_cache()->Get(TranscendentalCache::COS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006789}
6790
6791
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006792RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_exp) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006793 NoHandleAllocation ha;
6794 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006795 isolate->counters()->math_exp()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006796
6797 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006798 return isolate->transcendental_cache()->Get(TranscendentalCache::EXP, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006799}
6800
6801
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006802RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_floor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006803 NoHandleAllocation ha;
6804 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006805 isolate->counters()->math_floor()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006806
6807 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006808 return isolate->heap()->NumberFromDouble(floor(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006809}
6810
6811
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006812RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_log) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006813 NoHandleAllocation ha;
6814 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006815 isolate->counters()->math_log()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006816
6817 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006818 return isolate->transcendental_cache()->Get(TranscendentalCache::LOG, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006819}
6820
6821
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006822RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006823 NoHandleAllocation ha;
6824 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006825 isolate->counters()->math_pow()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006826
6827 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006828
6829 // If the second argument is a smi, it is much faster to call the
6830 // custom powi() function than the generic pow().
6831 if (args[1]->IsSmi()) {
6832 int y = Smi::cast(args[1])->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006833 return isolate->heap()->NumberFromDouble(power_double_int(x, y));
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006834 }
6835
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006836 CONVERT_DOUBLE_CHECKED(y, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006837 return isolate->heap()->AllocateHeapNumber(power_double_double(x, y));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006838}
6839
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006840// Fast version of Math.pow if we know that y is not an integer and
6841// y is not -0.5 or 0.5. Used as slowcase from codegen.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006842RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow_cfunction) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006843 NoHandleAllocation ha;
6844 ASSERT(args.length() == 2);
6845 CONVERT_DOUBLE_CHECKED(x, args[0]);
6846 CONVERT_DOUBLE_CHECKED(y, args[1]);
6847 if (y == 0) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006848 return Smi::FromInt(1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006849 } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006850 return isolate->heap()->nan_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006851 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006852 return isolate->heap()->AllocateHeapNumber(pow(x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006853 }
6854}
6855
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006856
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006857RUNTIME_FUNCTION(MaybeObject*, Runtime_RoundNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006858 NoHandleAllocation ha;
6859 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006860 isolate->counters()->math_round()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006861
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006862 if (!args[0]->IsHeapNumber()) {
6863 // Must be smi. Return the argument unchanged for all the other types
6864 // to make fuzz-natives test happy.
6865 return args[0];
6866 }
6867
6868 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
6869
6870 double value = number->value();
6871 int exponent = number->get_exponent();
6872 int sign = number->get_sign();
6873
danno@chromium.org160a7b02011-04-18 15:51:38 +00006874 if (exponent < -1) {
6875 // Number in range ]-0.5..0.5[. These always round to +/-zero.
6876 if (sign) return isolate->heap()->minus_zero_value();
6877 return Smi::FromInt(0);
6878 }
6879
6880 // We compare with kSmiValueSize - 2 because (2^30 - 0.1) has exponent 29 and
6881 // should be rounded to 2^30, which is not smi (for 31-bit smis, similar
6882 // agument holds for 32-bit smis).
6883 if (!sign && exponent < kSmiValueSize - 2) {
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006884 return Smi::FromInt(static_cast<int>(value + 0.5));
6885 }
6886
6887 // If the magnitude is big enough, there's no place for fraction part. If we
6888 // try to add 0.5 to this number, 1.0 will be added instead.
6889 if (exponent >= 52) {
6890 return number;
6891 }
6892
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006893 if (sign && value >= -0.5) return isolate->heap()->minus_zero_value();
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006894
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006895 // Do not call NumberFromDouble() to avoid extra checks.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006896 return isolate->heap()->AllocateHeapNumber(floor(value + 0.5));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006897}
6898
6899
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006900RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006901 NoHandleAllocation ha;
6902 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006903 isolate->counters()->math_sin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006904
6905 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006906 return isolate->transcendental_cache()->Get(TranscendentalCache::SIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006907}
6908
6909
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006910RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sqrt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006911 NoHandleAllocation ha;
6912 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006913 isolate->counters()->math_sqrt()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006914
6915 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006916 return isolate->heap()->AllocateHeapNumber(sqrt(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006917}
6918
6919
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006920RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_tan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006921 NoHandleAllocation ha;
6922 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006923 isolate->counters()->math_tan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006924
6925 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006926 return isolate->transcendental_cache()->Get(TranscendentalCache::TAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006927}
6928
6929
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006930static int MakeDay(int year, int month, int day) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006931 static const int day_from_month[] = {0, 31, 59, 90, 120, 151,
6932 181, 212, 243, 273, 304, 334};
6933 static const int day_from_month_leap[] = {0, 31, 60, 91, 121, 152,
6934 182, 213, 244, 274, 305, 335};
6935
6936 year += month / 12;
6937 month %= 12;
6938 if (month < 0) {
6939 year--;
6940 month += 12;
6941 }
6942
6943 ASSERT(month >= 0);
6944 ASSERT(month < 12);
6945
6946 // year_delta is an arbitrary number such that:
6947 // a) year_delta = -1 (mod 400)
6948 // b) year + year_delta > 0 for years in the range defined by
6949 // ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of
6950 // Jan 1 1970. This is required so that we don't run into integer
6951 // division of negative numbers.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006952 // c) there shouldn't be an overflow for 32-bit integers in the following
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006953 // operations.
6954 static const int year_delta = 399999;
6955 static const int base_day = 365 * (1970 + year_delta) +
6956 (1970 + year_delta) / 4 -
6957 (1970 + year_delta) / 100 +
6958 (1970 + year_delta) / 400;
6959
6960 int year1 = year + year_delta;
6961 int day_from_year = 365 * year1 +
6962 year1 / 4 -
6963 year1 / 100 +
6964 year1 / 400 -
6965 base_day;
6966
6967 if (year % 4 || (year % 100 == 0 && year % 400 != 0)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006968 return day_from_year + day_from_month[month] + day - 1;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006969 }
6970
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006971 return day_from_year + day_from_month_leap[month] + day - 1;
6972}
6973
6974
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006975RUNTIME_FUNCTION(MaybeObject*, Runtime_DateMakeDay) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006976 NoHandleAllocation ha;
6977 ASSERT(args.length() == 3);
6978
6979 CONVERT_SMI_CHECKED(year, args[0]);
6980 CONVERT_SMI_CHECKED(month, args[1]);
6981 CONVERT_SMI_CHECKED(date, args[2]);
6982
6983 return Smi::FromInt(MakeDay(year, month, date));
6984}
6985
6986
6987static const int kDays4Years[] = {0, 365, 2 * 365, 3 * 365 + 1};
6988static const int kDaysIn4Years = 4 * 365 + 1;
6989static const int kDaysIn100Years = 25 * kDaysIn4Years - 1;
6990static const int kDaysIn400Years = 4 * kDaysIn100Years + 1;
6991static const int kDays1970to2000 = 30 * 365 + 7;
6992static const int kDaysOffset = 1000 * kDaysIn400Years + 5 * kDaysIn400Years -
6993 kDays1970to2000;
6994static const int kYearsOffset = 400000;
6995
6996static const char kDayInYear[] = {
6997 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6998 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6999 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7000 22, 23, 24, 25, 26, 27, 28,
7001 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7002 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7003 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7004 22, 23, 24, 25, 26, 27, 28, 29, 30,
7005 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7006 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7007 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7008 22, 23, 24, 25, 26, 27, 28, 29, 30,
7009 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7010 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7011 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7012 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7013 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7014 22, 23, 24, 25, 26, 27, 28, 29, 30,
7015 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7016 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7017 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7018 22, 23, 24, 25, 26, 27, 28, 29, 30,
7019 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7020 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7021
7022 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7023 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7024 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7025 22, 23, 24, 25, 26, 27, 28,
7026 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7027 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7028 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7029 22, 23, 24, 25, 26, 27, 28, 29, 30,
7030 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7031 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7032 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7033 22, 23, 24, 25, 26, 27, 28, 29, 30,
7034 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7035 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7036 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7037 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7038 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7039 22, 23, 24, 25, 26, 27, 28, 29, 30,
7040 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7041 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7042 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7043 22, 23, 24, 25, 26, 27, 28, 29, 30,
7044 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7045 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7046
7047 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7048 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7049 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7050 22, 23, 24, 25, 26, 27, 28, 29,
7051 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7052 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7053 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7054 22, 23, 24, 25, 26, 27, 28, 29, 30,
7055 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7056 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7057 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7058 22, 23, 24, 25, 26, 27, 28, 29, 30,
7059 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7060 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7061 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7062 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7063 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7064 22, 23, 24, 25, 26, 27, 28, 29, 30,
7065 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7066 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7067 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7068 22, 23, 24, 25, 26, 27, 28, 29, 30,
7069 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7070 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7071
7072 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7073 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7074 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7075 22, 23, 24, 25, 26, 27, 28,
7076 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7077 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7078 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7079 22, 23, 24, 25, 26, 27, 28, 29, 30,
7080 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7081 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7082 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7083 22, 23, 24, 25, 26, 27, 28, 29, 30,
7084 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7085 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7086 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7087 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7088 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7089 22, 23, 24, 25, 26, 27, 28, 29, 30,
7090 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7091 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7092 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7093 22, 23, 24, 25, 26, 27, 28, 29, 30,
7094 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7095 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
7096
7097static const char kMonthInYear[] = {
7098 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,
7099 0, 0, 0, 0, 0, 0,
7100 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,
7101 1, 1, 1,
7102 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,
7103 2, 2, 2, 2, 2, 2,
7104 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,
7105 3, 3, 3, 3, 3,
7106 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,
7107 4, 4, 4, 4, 4, 4,
7108 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,
7109 5, 5, 5, 5, 5,
7110 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,
7111 6, 6, 6, 6, 6, 6,
7112 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,
7113 7, 7, 7, 7, 7, 7,
7114 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,
7115 8, 8, 8, 8, 8,
7116 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,
7117 9, 9, 9, 9, 9, 9,
7118 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7119 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7120 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7121 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7122
7123 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,
7124 0, 0, 0, 0, 0, 0,
7125 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,
7126 1, 1, 1,
7127 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,
7128 2, 2, 2, 2, 2, 2,
7129 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,
7130 3, 3, 3, 3, 3,
7131 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,
7132 4, 4, 4, 4, 4, 4,
7133 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,
7134 5, 5, 5, 5, 5,
7135 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,
7136 6, 6, 6, 6, 6, 6,
7137 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,
7138 7, 7, 7, 7, 7, 7,
7139 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,
7140 8, 8, 8, 8, 8,
7141 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,
7142 9, 9, 9, 9, 9, 9,
7143 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7144 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7145 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7146 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7147
7148 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,
7149 0, 0, 0, 0, 0, 0,
7150 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,
7151 1, 1, 1, 1,
7152 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,
7153 2, 2, 2, 2, 2, 2,
7154 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,
7155 3, 3, 3, 3, 3,
7156 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,
7157 4, 4, 4, 4, 4, 4,
7158 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,
7159 5, 5, 5, 5, 5,
7160 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,
7161 6, 6, 6, 6, 6, 6,
7162 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,
7163 7, 7, 7, 7, 7, 7,
7164 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,
7165 8, 8, 8, 8, 8,
7166 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,
7167 9, 9, 9, 9, 9, 9,
7168 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7169 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7170 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7171 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7172
7173 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,
7174 0, 0, 0, 0, 0, 0,
7175 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,
7176 1, 1, 1,
7177 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,
7178 2, 2, 2, 2, 2, 2,
7179 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,
7180 3, 3, 3, 3, 3,
7181 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,
7182 4, 4, 4, 4, 4, 4,
7183 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,
7184 5, 5, 5, 5, 5,
7185 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,
7186 6, 6, 6, 6, 6, 6,
7187 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,
7188 7, 7, 7, 7, 7, 7,
7189 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,
7190 8, 8, 8, 8, 8,
7191 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,
7192 9, 9, 9, 9, 9, 9,
7193 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7194 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7195 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7196 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11};
7197
7198
7199// This function works for dates from 1970 to 2099.
7200static inline void DateYMDFromTimeAfter1970(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007201 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007202#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007203 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007204#endif
7205
7206 year = 1970 + (4 * date + 2) / kDaysIn4Years;
7207 date %= kDaysIn4Years;
7208
7209 month = kMonthInYear[date];
7210 day = kDayInYear[date];
7211
7212 ASSERT(MakeDay(year, month, day) == save_date);
7213}
7214
7215
7216static inline void DateYMDFromTimeSlow(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007217 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007218#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007219 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007220#endif
7221
7222 date += kDaysOffset;
7223 year = 400 * (date / kDaysIn400Years) - kYearsOffset;
7224 date %= kDaysIn400Years;
7225
7226 ASSERT(MakeDay(year, 0, 1) + date == save_date);
7227
7228 date--;
7229 int yd1 = date / kDaysIn100Years;
7230 date %= kDaysIn100Years;
7231 year += 100 * yd1;
7232
7233 date++;
7234 int yd2 = date / kDaysIn4Years;
7235 date %= kDaysIn4Years;
7236 year += 4 * yd2;
7237
7238 date--;
7239 int yd3 = date / 365;
7240 date %= 365;
7241 year += yd3;
7242
7243 bool is_leap = (!yd1 || yd2) && !yd3;
7244
7245 ASSERT(date >= -1);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007246 ASSERT(is_leap || (date >= 0));
7247 ASSERT((date < 365) || (is_leap && (date < 366)));
7248 ASSERT(is_leap == ((year % 4 == 0) && (year % 100 || (year % 400 == 0))));
7249 ASSERT(is_leap || ((MakeDay(year, 0, 1) + date) == save_date));
7250 ASSERT(!is_leap || ((MakeDay(year, 0, 1) + date + 1) == save_date));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007251
7252 if (is_leap) {
7253 day = kDayInYear[2*365 + 1 + date];
7254 month = kMonthInYear[2*365 + 1 + date];
7255 } else {
7256 day = kDayInYear[date];
7257 month = kMonthInYear[date];
7258 }
7259
7260 ASSERT(MakeDay(year, month, day) == save_date);
7261}
7262
7263
7264static inline void DateYMDFromTime(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007265 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007266 if (date >= 0 && date < 32 * kDaysIn4Years) {
7267 DateYMDFromTimeAfter1970(date, year, month, day);
7268 } else {
7269 DateYMDFromTimeSlow(date, year, month, day);
7270 }
7271}
7272
7273
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007274RUNTIME_FUNCTION(MaybeObject*, Runtime_DateYMDFromTime) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007275 NoHandleAllocation ha;
7276 ASSERT(args.length() == 2);
7277
7278 CONVERT_DOUBLE_CHECKED(t, args[0]);
7279 CONVERT_CHECKED(JSArray, res_array, args[1]);
7280
7281 int year, month, day;
7282 DateYMDFromTime(static_cast<int>(floor(t / 86400000)), year, month, day);
7283
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007284 RUNTIME_ASSERT(res_array->elements()->map() ==
7285 isolate->heap()->fixed_array_map());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00007286 FixedArray* elms = FixedArray::cast(res_array->elements());
7287 RUNTIME_ASSERT(elms->length() == 3);
7288
7289 elms->set(0, Smi::FromInt(year));
7290 elms->set(1, Smi::FromInt(month));
7291 elms->set(2, Smi::FromInt(day));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007292
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007293 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007294}
7295
7296
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007297RUNTIME_FUNCTION(MaybeObject*, Runtime_NewArgumentsFast) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007298 NoHandleAllocation ha;
7299 ASSERT(args.length() == 3);
7300
7301 JSFunction* callee = JSFunction::cast(args[0]);
7302 Object** parameters = reinterpret_cast<Object**>(args[1]);
7303 const int length = Smi::cast(args[2])->value();
7304
lrn@chromium.org303ada72010-10-27 09:33:13 +00007305 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007306 { MaybeObject* maybe_result =
7307 isolate->heap()->AllocateArgumentsObject(callee, length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007308 if (!maybe_result->ToObject(&result)) return maybe_result;
7309 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007310 // Allocate the elements if needed.
7311 if (length > 0) {
7312 // Allocate the fixed array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007313 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007314 { MaybeObject* maybe_obj = isolate->heap()->AllocateRawFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007315 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7316 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007317
7318 AssertNoAllocation no_gc;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007319 FixedArray* array = reinterpret_cast<FixedArray*>(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007320 array->set_map(isolate->heap()->fixed_array_map());
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007321 array->set_length(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007322
7323 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007324 for (int i = 0; i < length; i++) {
7325 array->set(i, *--parameters, mode);
7326 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007327 JSObject::cast(result)->set_elements(FixedArray::cast(obj));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007328 }
7329 return result;
7330}
7331
7332
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007333RUNTIME_FUNCTION(MaybeObject*, Runtime_NewClosure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007334 HandleScope scope(isolate);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007335 ASSERT(args.length() == 3);
ager@chromium.org3811b432009-10-28 14:53:37 +00007336 CONVERT_ARG_CHECKED(Context, context, 0);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007337 CONVERT_ARG_CHECKED(SharedFunctionInfo, shared, 1);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007338 CONVERT_BOOLEAN_CHECKED(pretenure, args[2]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007339
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007340 // Allocate global closures in old space and allocate local closures
7341 // in new space. Additionally pretenure closures that are assigned
7342 // directly to properties.
7343 pretenure = pretenure || (context->global_context() == *context);
7344 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007345 Handle<JSFunction> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007346 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
7347 context,
7348 pretenure_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007349 return *result;
7350}
7351
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007352
7353static SmartPointer<Object**> GetNonBoundArguments(int bound_argc,
7354 int* total_argc) {
7355 // Find frame containing arguments passed to the caller.
7356 JavaScriptFrameIterator it;
7357 JavaScriptFrame* frame = it.frame();
7358 List<JSFunction*> functions(2);
7359 frame->GetFunctions(&functions);
7360 if (functions.length() > 1) {
7361 int inlined_frame_index = functions.length() - 1;
7362 JSFunction* inlined_function = functions[inlined_frame_index];
7363 int args_count = inlined_function->shared()->formal_parameter_count();
7364 ScopedVector<SlotRef> args_slots(args_count);
7365 SlotRef::ComputeSlotMappingForArguments(frame,
7366 inlined_frame_index,
7367 &args_slots);
7368
7369 *total_argc = bound_argc + args_count;
7370 SmartPointer<Object**> param_data(NewArray<Object**>(*total_argc));
7371 for (int i = 0; i < args_count; i++) {
7372 Handle<Object> val = args_slots[i].GetValue();
7373 param_data[bound_argc + i] = val.location();
7374 }
7375 return param_data;
7376 } else {
7377 it.AdvanceToArgumentsFrame();
7378 frame = it.frame();
7379 int args_count = frame->ComputeParametersCount();
7380
7381 *total_argc = bound_argc + args_count;
7382 SmartPointer<Object**> param_data(NewArray<Object**>(*total_argc));
7383 for (int i = 0; i < args_count; i++) {
7384 Handle<Object> val = Handle<Object>(frame->GetParameter(i));
7385 param_data[bound_argc + i] = val.location();
7386 }
7387 return param_data;
7388 }
7389}
7390
7391
7392RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObjectFromBound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007393 HandleScope scope(isolate);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007394 ASSERT(args.length() == 2);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007395 // First argument is a function to use as a constructor.
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007396 CONVERT_ARG_CHECKED(JSFunction, function, 0);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007397
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007398 // Second argument is either null or an array of bound arguments.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007399 Handle<FixedArray> bound_args;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007400 int bound_argc = 0;
7401 if (!args[1]->IsNull()) {
7402 CONVERT_ARG_CHECKED(JSArray, params, 1);
7403 RUNTIME_ASSERT(params->HasFastElements());
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007404 bound_args = Handle<FixedArray>(FixedArray::cast(params->elements()));
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007405 bound_argc = Smi::cast(params->length())->value();
7406 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007407
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007408 int total_argc = 0;
7409 SmartPointer<Object**> param_data =
7410 GetNonBoundArguments(bound_argc, &total_argc);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007411 for (int i = 0; i < bound_argc; i++) {
7412 Handle<Object> val = Handle<Object>(bound_args->get(i));
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007413 param_data[i] = val.location();
7414 }
7415
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007416 bool exception = false;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007417 Handle<Object> result =
7418 Execution::New(function, total_argc, *param_data, &exception);
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007419 if (exception) {
7420 return Failure::Exception();
7421 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007422
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007423 ASSERT(!result.is_null());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007424 return *result;
7425}
7426
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007427
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007428static void TrySettingInlineConstructStub(Isolate* isolate,
7429 Handle<JSFunction> function) {
7430 Handle<Object> prototype = isolate->factory()->null_value();
ager@chromium.org5c838252010-02-19 08:53:10 +00007431 if (function->has_instance_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007432 prototype = Handle<Object>(function->instance_prototype(), isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00007433 }
7434 if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007435 ConstructStubCompiler compiler;
ager@chromium.orgbeb25712010-11-29 08:02:25 +00007436 MaybeObject* code = compiler.CompileConstructStub(*function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007437 if (!code->IsFailure()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007438 function->shared()->set_construct_stub(
7439 Code::cast(code->ToObjectUnchecked()));
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007440 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007441 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007442}
7443
7444
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007445RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007446 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007447 ASSERT(args.length() == 1);
7448
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007449 Handle<Object> constructor = args.at<Object>(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007450
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007451 // If the constructor isn't a proper function we throw a type error.
7452 if (!constructor->IsJSFunction()) {
7453 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
7454 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007455 isolate->factory()->NewTypeError("not_constructor", arguments);
7456 return isolate->Throw(*type_error);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007457 }
7458
7459 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007460
7461 // If function should not have prototype, construction is not allowed. In this
7462 // case generated code bailouts here, since function has no initial_map.
7463 if (!function->should_have_prototype()) {
7464 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
7465 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007466 isolate->factory()->NewTypeError("not_constructor", arguments);
7467 return isolate->Throw(*type_error);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007468 }
7469
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007470#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007471 Debug* debug = isolate->debug();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007472 // Handle stepping into constructors if step into is active.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007473 if (debug->StepInActive()) {
7474 debug->HandleStepIn(function, Handle<Object>::null(), 0, true);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007475 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007476#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007477
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007478 if (function->has_initial_map()) {
7479 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007480 // The 'Function' function ignores the receiver object when
7481 // called using 'new' and creates a new JSFunction object that
7482 // is returned. The receiver object is only used for error
7483 // reporting if an error occurs when constructing the new
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007484 // JSFunction. FACTORY->NewJSObject() should not be used to
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007485 // allocate JSFunctions since it does not properly initialize
7486 // the shared part of the function. Since the receiver is
7487 // ignored anyway, we use the global object as the receiver
7488 // instead of a new JSFunction object. This way, errors are
7489 // reported the same way whether or not 'Function' is called
7490 // using 'new'.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007491 return isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007492 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007493 }
7494
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007495 // The function should be compiled for the optimization hints to be
7496 // available. We cannot use EnsureCompiled because that forces a
7497 // compilation through the shared function info which makes it
7498 // impossible for us to optimize.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007499 Handle<SharedFunctionInfo> shared(function->shared(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007500 if (!function->is_compiled()) CompileLazy(function, CLEAR_EXCEPTION);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007501
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007502 if (!function->has_initial_map() &&
7503 shared->IsInobjectSlackTrackingInProgress()) {
7504 // The tracking is already in progress for another function. We can only
7505 // track one initial_map at a time, so we force the completion before the
7506 // function is called as a constructor for the first time.
7507 shared->CompleteInobjectSlackTracking();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007508 }
7509
7510 bool first_allocation = !shared->live_objects_may_exist();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007511 Handle<JSObject> result = isolate->factory()->NewJSObject(function);
7512 RETURN_IF_EMPTY_HANDLE(isolate, result);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007513 // Delay setting the stub if inobject slack tracking is in progress.
7514 if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007515 TrySettingInlineConstructStub(isolate, function);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007516 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007517
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007518 isolate->counters()->constructed_objects()->Increment();
7519 isolate->counters()->constructed_objects_runtime()->Increment();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007520
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007521 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007522}
7523
7524
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007525RUNTIME_FUNCTION(MaybeObject*, Runtime_FinalizeInstanceSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007526 HandleScope scope(isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007527 ASSERT(args.length() == 1);
7528
7529 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7530 function->shared()->CompleteInobjectSlackTracking();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007531 TrySettingInlineConstructStub(isolate, function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007532
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007533 return isolate->heap()->undefined_value();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007534}
7535
7536
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007537RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007538 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007539 ASSERT(args.length() == 1);
7540
7541 Handle<JSFunction> function = args.at<JSFunction>(0);
7542#ifdef DEBUG
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00007543 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007544 PrintF("[lazy: ");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007545 function->PrintName();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007546 PrintF("]\n");
7547 }
7548#endif
7549
kasperl@chromium.org71affb52009-05-26 05:44:31 +00007550 // Compile the target function. Here we compile using CompileLazyInLoop in
7551 // order to get the optimized version. This helps code like delta-blue
7552 // that calls performance-critical routines through constructors. A
7553 // constructor call doesn't use a CallIC, it uses a LoadIC followed by a
7554 // direct call. Since the in-loop tracking takes place through CallICs
7555 // this means that things called through constructors are never known to
7556 // be in loops. We compile them as if they are in loops here just in case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007557 ASSERT(!function->is_compiled());
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007558 if (!CompileLazyInLoop(function, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007559 return Failure::Exception();
7560 }
7561
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007562 // All done. Return the compiled code.
7563 ASSERT(function->is_compiled());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007564 return function->code();
7565}
7566
7567
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007568RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyRecompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007569 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007570 ASSERT(args.length() == 1);
7571 Handle<JSFunction> function = args.at<JSFunction>(0);
7572 // If the function is not optimizable or debugger is active continue using the
7573 // code from the full compiler.
7574 if (!function->shared()->code()->optimizable() ||
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007575 isolate->DebuggerHasBreakPoints()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007576 if (FLAG_trace_opt) {
7577 PrintF("[failed to optimize ");
7578 function->PrintName();
7579 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n",
7580 function->shared()->code()->optimizable() ? "T" : "F",
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007581 isolate->DebuggerHasBreakPoints() ? "T" : "F");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007582 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007583 function->ReplaceCode(function->shared()->code());
7584 return function->code();
7585 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007586 if (CompileOptimized(function, AstNode::kNoNumber, CLEAR_EXCEPTION)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007587 return function->code();
7588 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007589 if (FLAG_trace_opt) {
7590 PrintF("[failed to optimize ");
7591 function->PrintName();
7592 PrintF(": optimized compilation failed]\n");
7593 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007594 function->ReplaceCode(function->shared()->code());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007595 return function->code();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007596}
7597
7598
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007599RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007600 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007601 ASSERT(args.length() == 1);
7602 RUNTIME_ASSERT(args[0]->IsSmi());
7603 Deoptimizer::BailoutType type =
7604 static_cast<Deoptimizer::BailoutType>(Smi::cast(args[0])->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007605 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
7606 ASSERT(isolate->heap()->IsAllocationAllowed());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007607 int frames = deoptimizer->output_count();
7608
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00007609 deoptimizer->MaterializeHeapNumbers();
7610 delete deoptimizer;
7611
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007612 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007613 JavaScriptFrame* frame = NULL;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00007614 for (int i = 0; i < frames - 1; i++) it.Advance();
7615 frame = it.frame();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007616
7617 RUNTIME_ASSERT(frame->function()->IsJSFunction());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007618 Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007619 Handle<Object> arguments;
7620 for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007621 if (frame->GetExpression(i) == isolate->heap()->arguments_marker()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007622 if (arguments.is_null()) {
7623 // FunctionGetArguments can't throw an exception, so cast away the
7624 // doubt with an assert.
7625 arguments = Handle<Object>(
7626 Accessors::FunctionGetArguments(*function,
7627 NULL)->ToObjectUnchecked());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007628 ASSERT(*arguments != isolate->heap()->null_value());
7629 ASSERT(*arguments != isolate->heap()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007630 }
7631 frame->SetExpression(i, *arguments);
7632 }
7633 }
7634
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007635 isolate->compilation_cache()->MarkForLazyOptimizing(function);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007636 if (type == Deoptimizer::EAGER) {
7637 RUNTIME_ASSERT(function->IsOptimized());
7638 } else {
7639 RUNTIME_ASSERT(!function->IsOptimized());
7640 }
7641
7642 // Avoid doing too much work when running with --always-opt and keep
7643 // the optimized code around.
7644 if (FLAG_always_opt || type == Deoptimizer::LAZY) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007645 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007646 }
7647
7648 // Count the number of optimized activations of the function.
7649 int activations = 0;
7650 while (!it.done()) {
7651 JavaScriptFrame* frame = it.frame();
7652 if (frame->is_optimized() && frame->function() == *function) {
7653 activations++;
7654 }
7655 it.Advance();
7656 }
7657
7658 // TODO(kasperl): For now, we cannot support removing the optimized
7659 // code when we have recursive invocations of the same function.
7660 if (activations == 0) {
7661 if (FLAG_trace_deopt) {
7662 PrintF("[removing optimized code for: ");
7663 function->PrintName();
7664 PrintF("]\n");
7665 }
7666 function->ReplaceCode(function->shared()->code());
7667 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007668 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007669}
7670
7671
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007672RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyOSR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007673 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007674 delete deoptimizer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007675 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007676}
7677
7678
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007679RUNTIME_FUNCTION(MaybeObject*, Runtime_DeoptimizeFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007680 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007681 ASSERT(args.length() == 1);
7682 CONVERT_ARG_CHECKED(JSFunction, function, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007683 if (!function->IsOptimized()) return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007684
7685 Deoptimizer::DeoptimizeFunction(*function);
7686
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007687 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007688}
7689
7690
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00007691RUNTIME_FUNCTION(MaybeObject*, Runtime_OptimizeFunctionOnNextCall) {
7692 HandleScope scope(isolate);
7693 ASSERT(args.length() == 1);
7694 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7695 if (!function->IsOptimizable()) return isolate->heap()->undefined_value();
7696 function->MarkForLazyRecompilation();
7697 return isolate->heap()->undefined_value();
7698}
7699
7700
lrn@chromium.org1c092762011-05-09 09:42:16 +00007701RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationStatus) {
7702 HandleScope scope(isolate);
7703 ASSERT(args.length() == 1);
7704 if (!V8::UseCrankshaft()) {
7705 return Smi::FromInt(4); // 4 == "never".
7706 }
7707 if (FLAG_always_opt) {
7708 return Smi::FromInt(3); // 3 == "always".
7709 }
7710 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7711 return function->IsOptimized() ? Smi::FromInt(1) // 1 == "yes".
7712 : Smi::FromInt(2); // 2 == "no".
7713}
7714
7715
7716RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationCount) {
7717 HandleScope scope(isolate);
7718 ASSERT(args.length() == 1);
7719 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7720 return Smi::FromInt(function->shared()->opt_count());
7721}
7722
7723
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007724RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007725 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007726 ASSERT(args.length() == 1);
7727 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7728
7729 // We're not prepared to handle a function with arguments object.
7730 ASSERT(!function->shared()->scope_info()->HasArgumentsShadow());
7731
7732 // We have hit a back edge in an unoptimized frame for a function that was
7733 // selected for on-stack replacement. Find the unoptimized code object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007734 Handle<Code> unoptimized(function->shared()->code(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007735 // Keep track of whether we've succeeded in optimizing.
7736 bool succeeded = unoptimized->optimizable();
7737 if (succeeded) {
7738 // If we are trying to do OSR when there are already optimized
7739 // activations of the function, it means (a) the function is directly or
7740 // indirectly recursive and (b) an optimized invocation has been
7741 // deoptimized so that we are currently in an unoptimized activation.
7742 // Check for optimized activations of this function.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007743 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007744 while (succeeded && !it.done()) {
7745 JavaScriptFrame* frame = it.frame();
7746 succeeded = !frame->is_optimized() || frame->function() != *function;
7747 it.Advance();
7748 }
7749 }
7750
7751 int ast_id = AstNode::kNoNumber;
7752 if (succeeded) {
7753 // The top JS function is this one, the PC is somewhere in the
7754 // unoptimized code.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007755 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007756 JavaScriptFrame* frame = it.frame();
7757 ASSERT(frame->function() == *function);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007758 ASSERT(frame->LookupCode() == *unoptimized);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007759 ASSERT(unoptimized->contains(frame->pc()));
7760
7761 // Use linear search of the unoptimized code's stack check table to find
7762 // the AST id matching the PC.
7763 Address start = unoptimized->instruction_start();
7764 unsigned target_pc_offset = static_cast<unsigned>(frame->pc() - start);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007765 Address table_cursor = start + unoptimized->stack_check_table_offset();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007766 uint32_t table_length = Memory::uint32_at(table_cursor);
7767 table_cursor += kIntSize;
7768 for (unsigned i = 0; i < table_length; ++i) {
7769 // Table entries are (AST id, pc offset) pairs.
7770 uint32_t pc_offset = Memory::uint32_at(table_cursor + kIntSize);
7771 if (pc_offset == target_pc_offset) {
7772 ast_id = static_cast<int>(Memory::uint32_at(table_cursor));
7773 break;
7774 }
7775 table_cursor += 2 * kIntSize;
7776 }
7777 ASSERT(ast_id != AstNode::kNoNumber);
7778 if (FLAG_trace_osr) {
7779 PrintF("[replacing on-stack at AST id %d in ", ast_id);
7780 function->PrintName();
7781 PrintF("]\n");
7782 }
7783
7784 // Try to compile the optimized code. A true return value from
7785 // CompileOptimized means that compilation succeeded, not necessarily
7786 // that optimization succeeded.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007787 if (CompileOptimized(function, ast_id, CLEAR_EXCEPTION) &&
7788 function->IsOptimized()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007789 DeoptimizationInputData* data = DeoptimizationInputData::cast(
7790 function->code()->deoptimization_data());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007791 if (data->OsrPcOffset()->value() >= 0) {
7792 if (FLAG_trace_osr) {
7793 PrintF("[on-stack replacement offset %d in optimized code]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007794 data->OsrPcOffset()->value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007795 }
7796 ASSERT(data->OsrAstId()->value() == ast_id);
7797 } else {
7798 // We may never generate the desired OSR entry if we emit an
7799 // early deoptimize.
7800 succeeded = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007801 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007802 } else {
7803 succeeded = false;
7804 }
7805 }
7806
7807 // Revert to the original stack checks in the original unoptimized code.
7808 if (FLAG_trace_osr) {
7809 PrintF("[restoring original stack checks in ");
7810 function->PrintName();
7811 PrintF("]\n");
7812 }
7813 StackCheckStub check_stub;
7814 Handle<Code> check_code = check_stub.GetCode();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00007815 Handle<Code> replacement_code = isolate->builtins()->OnStackReplacement();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007816 Deoptimizer::RevertStackCheckCode(*unoptimized,
7817 *check_code,
7818 *replacement_code);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007819
7820 // Allow OSR only at nesting level zero again.
7821 unoptimized->set_allow_osr_at_loop_nesting_level(0);
7822
7823 // If the optimization attempt succeeded, return the AST id tagged as a
7824 // smi. This tells the builtin that we need to translate the unoptimized
7825 // frame to an optimized one.
7826 if (succeeded) {
7827 ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
7828 return Smi::FromInt(ast_id);
7829 } else {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007830 if (function->IsMarkedForLazyRecompilation()) {
7831 function->ReplaceCode(function->shared()->code());
7832 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007833 return Smi::FromInt(-1);
7834 }
7835}
7836
7837
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007838RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007839 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007840 ASSERT(args.length() == 1);
7841 RUNTIME_ASSERT(!args[0]->IsJSFunction());
7842 return *Execution::GetFunctionDelegate(args.at<Object>(0));
7843}
7844
7845
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007846RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructorDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007847 HandleScope scope(isolate);
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00007848 ASSERT(args.length() == 1);
7849 RUNTIME_ASSERT(!args[0]->IsJSFunction());
7850 return *Execution::GetConstructorDelegate(args.at<Object>(0));
7851}
7852
7853
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007854RUNTIME_FUNCTION(MaybeObject*, Runtime_NewContext) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007855 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00007856 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007857
kasper.lund7276f142008-07-30 08:49:36 +00007858 CONVERT_CHECKED(JSFunction, function, args[0]);
ager@chromium.orgb5737492010-07-15 09:29:43 +00007859 int length = function->shared()->scope_info()->NumberOfContextSlots();
lrn@chromium.org303ada72010-10-27 09:33:13 +00007860 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007861 { MaybeObject* maybe_result =
7862 isolate->heap()->AllocateFunctionContext(length, function);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007863 if (!maybe_result->ToObject(&result)) return maybe_result;
7864 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007865
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007866 isolate->set_context(Context::cast(result));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007867
kasper.lund7276f142008-07-30 08:49:36 +00007868 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007869}
7870
lrn@chromium.org303ada72010-10-27 09:33:13 +00007871
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007872MUST_USE_RESULT static MaybeObject* PushContextHelper(Isolate* isolate,
7873 Object* object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00007874 bool is_catch_context) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007875 // Convert the object to a proper JavaScript object.
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007876 Object* js_object = object;
7877 if (!js_object->IsJSObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007878 MaybeObject* maybe_js_object = js_object->ToObject();
7879 if (!maybe_js_object->ToObject(&js_object)) {
7880 if (!Failure::cast(maybe_js_object)->IsInternalError()) {
7881 return maybe_js_object;
7882 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007883 HandleScope scope(isolate);
7884 Handle<Object> handle(object, isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007885 Handle<Object> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007886 isolate->factory()->NewTypeError("with_expression",
7887 HandleVector(&handle, 1));
7888 return isolate->Throw(*result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007889 }
7890 }
7891
lrn@chromium.org303ada72010-10-27 09:33:13 +00007892 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007893 { MaybeObject* maybe_result = isolate->heap()->AllocateWithContext(
7894 isolate->context(), JSObject::cast(js_object), is_catch_context);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007895 if (!maybe_result->ToObject(&result)) return maybe_result;
7896 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007897
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007898 Context* context = Context::cast(result);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007899 isolate->set_context(context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007900
kasper.lund7276f142008-07-30 08:49:36 +00007901 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007902}
7903
7904
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007905RUNTIME_FUNCTION(MaybeObject*, Runtime_PushContext) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007906 NoHandleAllocation ha;
7907 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007908 return PushContextHelper(isolate, args[0], false);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007909}
7910
7911
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007912RUNTIME_FUNCTION(MaybeObject*, Runtime_PushCatchContext) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007913 NoHandleAllocation ha;
7914 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007915 return PushContextHelper(isolate, args[0], true);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007916}
7917
7918
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007919RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007920 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007921 ASSERT(args.length() == 2);
7922
7923 CONVERT_ARG_CHECKED(Context, context, 0);
7924 CONVERT_ARG_CHECKED(String, name, 1);
7925
7926 int index;
7927 PropertyAttributes attributes;
7928 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007929 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007930
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007931 // If the slot was not found the result is true.
7932 if (holder.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007933 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007934 }
7935
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007936 // If the slot was found in a context, it should be DONT_DELETE.
7937 if (holder->IsContext()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007938 return isolate->heap()->false_value();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007939 }
7940
7941 // The slot was found in a JSObject, either a context extension object,
7942 // the global object, or an arguments object. Try to delete it
7943 // (respecting DONT_DELETE). For consistency with V8's usual behavior,
7944 // which allows deleting all parameters in functions that mention
7945 // 'arguments', we do this even for the case of slots found on an
7946 // arguments object. The slot was found on an arguments object if the
7947 // index is non-negative.
7948 Handle<JSObject> object = Handle<JSObject>::cast(holder);
7949 if (index >= 0) {
7950 return object->DeleteElement(index, JSObject::NORMAL_DELETION);
7951 } else {
7952 return object->DeleteProperty(*name, JSObject::NORMAL_DELETION);
7953 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007954}
7955
7956
ager@chromium.orga1645e22009-09-09 19:27:10 +00007957// A mechanism to return a pair of Object pointers in registers (if possible).
7958// How this is achieved is calling convention-dependent.
7959// All currently supported x86 compiles uses calling conventions that are cdecl
7960// variants where a 64-bit value is returned in two 32-bit registers
7961// (edx:eax on ia32, r1:r0 on ARM).
7962// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
7963// In Win64 calling convention, a struct of two pointers is returned in memory,
7964// allocated by the caller, and passed as a pointer in a hidden first parameter.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007965#ifdef V8_HOST_ARCH_64_BIT
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007966struct ObjectPair {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007967 MaybeObject* x;
7968 MaybeObject* y;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007969};
ager@chromium.orga1645e22009-09-09 19:27:10 +00007970
lrn@chromium.org303ada72010-10-27 09:33:13 +00007971static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007972 ObjectPair result = {x, y};
ager@chromium.orga1645e22009-09-09 19:27:10 +00007973 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
7974 // In Win64 they are assigned to a hidden first argument.
7975 return result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007976}
7977#else
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007978typedef uint64_t ObjectPair;
lrn@chromium.org303ada72010-10-27 09:33:13 +00007979static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007980 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007981 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007982}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007983#endif
7984
7985
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007986static inline MaybeObject* Unhole(Heap* heap,
7987 MaybeObject* x,
lrn@chromium.org303ada72010-10-27 09:33:13 +00007988 PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007989 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
7990 USE(attributes);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007991 return x->IsTheHole() ? heap->undefined_value() : x;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007992}
7993
7994
danno@chromium.org40cb8782011-05-25 07:58:50 +00007995static Object* ComputeReceiverForNonGlobal(Isolate* isolate,
7996 JSObject* holder) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007997 ASSERT(!holder->IsGlobalObject());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007998 Context* top = isolate->context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007999 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008000 JSFunction* context_extension_function =
8001 top->global_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008002 // If the holder isn't a context extension object, we just return it
8003 // as the receiver. This allows arguments objects to be used as
8004 // receivers, but only if they are put in the context scope chain
8005 // explicitly via a with-statement.
8006 Object* constructor = holder->map()->constructor();
8007 if (constructor != context_extension_function) return holder;
danno@chromium.org40cb8782011-05-25 07:58:50 +00008008 // Fall back to using the global object as the implicit receiver if
8009 // the property turns out to be a local variable allocated in a
8010 // context extension object - introduced via eval. Implicit global
8011 // receivers are indicated with the hole value.
8012 return isolate->heap()->the_hole_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008013}
8014
8015
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008016static ObjectPair LoadContextSlotHelper(Arguments args,
8017 Isolate* isolate,
8018 bool throw_error) {
8019 HandleScope scope(isolate);
ager@chromium.orga1645e22009-09-09 19:27:10 +00008020 ASSERT_EQ(2, args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008021
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008022 if (!args[0]->IsContext() || !args[1]->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008023 return MakePair(isolate->ThrowIllegalOperation(), NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008024 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008025 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008026 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008027
8028 int index;
8029 PropertyAttributes attributes;
8030 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008031 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008032
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008033 // If the index is non-negative, the slot has been found in a local
8034 // variable or a parameter. Read it from the context object or the
8035 // arguments object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008036 if (index >= 0) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008037 // If the "property" we were looking for is a local variable or an
8038 // argument in a context, the receiver is the global object; see
8039 // ECMA-262, 3rd., 10.1.6 and 10.2.3.
danno@chromium.org40cb8782011-05-25 07:58:50 +00008040 //
8041 // Use the hole as the receiver to signal that the receiver is
8042 // implicit and that the global receiver should be used.
8043 Handle<Object> receiver = isolate->factory()->the_hole_value();
lrn@chromium.org303ada72010-10-27 09:33:13 +00008044 MaybeObject* value = (holder->IsContext())
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008045 ? Context::cast(*holder)->get(index)
8046 : JSObject::cast(*holder)->GetElement(index);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008047 return MakePair(Unhole(isolate->heap(), value, attributes), *receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008048 }
8049
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008050 // If the holder is found, we read the property from it.
8051 if (!holder.is_null() && holder->IsJSObject()) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008052 ASSERT(Handle<JSObject>::cast(holder)->HasProperty(*name));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008053 JSObject* object = JSObject::cast(*holder);
danno@chromium.org40cb8782011-05-25 07:58:50 +00008054 Object* receiver;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008055 if (object->IsGlobalObject()) {
8056 receiver = GlobalObject::cast(object)->global_receiver();
8057 } else if (context->is_exception_holder(*holder)) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008058 // Use the hole as the receiver to signal that the receiver is
8059 // implicit and that the global receiver should be used.
8060 receiver = isolate->heap()->the_hole_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008061 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008062 receiver = ComputeReceiverForNonGlobal(isolate, object);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008063 }
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008064
8065 // GetProperty below can cause GC.
danno@chromium.org40cb8782011-05-25 07:58:50 +00008066 Handle<Object> receiver_handle(receiver);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008067
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008068 // No need to unhole the value here. This is taken care of by the
8069 // GetProperty function.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008070 MaybeObject* value = object->GetProperty(*name);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008071 return MakePair(value, *receiver_handle);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008072 }
8073
8074 if (throw_error) {
8075 // The property doesn't exist - throw exception.
8076 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008077 isolate->factory()->NewReferenceError("not_defined",
8078 HandleVector(&name, 1));
8079 return MakePair(isolate->Throw(*reference_error), NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008080 } else {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008081 // The property doesn't exist - return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008082 return MakePair(isolate->heap()->undefined_value(),
8083 isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008084 }
8085}
8086
8087
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008088RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008089 return LoadContextSlotHelper(args, isolate, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008090}
8091
8092
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008093RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlotNoReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008094 return LoadContextSlotHelper(args, isolate, false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008095}
8096
8097
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008098RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008099 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008100 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008101
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008102 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008103 CONVERT_ARG_CHECKED(Context, context, 1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008104 CONVERT_ARG_CHECKED(String, name, 2);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008105 CONVERT_SMI_CHECKED(strict_unchecked, args[3]);
8106 RUNTIME_ASSERT(strict_unchecked == kStrictMode ||
8107 strict_unchecked == kNonStrictMode);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008108 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(strict_unchecked);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008109
8110 int index;
8111 PropertyAttributes attributes;
8112 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008113 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008114
8115 if (index >= 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008116 if (holder->IsContext()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008117 // Ignore if read_only variable.
8118 if ((attributes & READ_ONLY) == 0) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008119 // Context is a fixed array and set cannot fail.
8120 Context::cast(*holder)->set(index, *value);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008121 } else if (strict_mode == kStrictMode) {
8122 // Setting read only property in strict mode.
8123 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008124 isolate->factory()->NewTypeError("strict_cannot_assign",
8125 HandleVector(&name, 1));
8126 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008127 }
8128 } else {
8129 ASSERT((attributes & READ_ONLY) == 0);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008130 Handle<Object> result =
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008131 SetElement(Handle<JSObject>::cast(holder), index, value, strict_mode);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008132 if (result.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008133 ASSERT(isolate->has_pending_exception());
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008134 return Failure::Exception();
8135 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008136 }
8137 return *value;
8138 }
8139
8140 // Slow case: The property is not in a FixedArray context.
8141 // It is either in an JSObject extension context or it was not found.
8142 Handle<JSObject> context_ext;
8143
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008144 if (!holder.is_null()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008145 // The property exists in the extension context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008146 context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008147 } else {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008148 // The property was not found.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008149 ASSERT(attributes == ABSENT);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008150
8151 if (strict_mode == kStrictMode) {
8152 // Throw in strict mode (assignment to undefined variable).
8153 Handle<Object> error =
8154 isolate->factory()->NewReferenceError(
8155 "not_defined", HandleVector(&name, 1));
8156 return isolate->Throw(*error);
8157 }
8158 // In non-strict mode, the property is stored in the global context.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008159 attributes = NONE;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008160 context_ext = Handle<JSObject>(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008161 }
8162
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008163 // Set the property, but ignore if read_only variable on the context
8164 // extension object itself.
8165 if ((attributes & READ_ONLY) == 0 ||
8166 (context_ext->GetLocalPropertyAttribute(*name) == ABSENT)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008167 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008168 isolate,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008169 SetProperty(context_ext, name, value, NONE, strict_mode));
8170 } else if (strict_mode == kStrictMode && (attributes & READ_ONLY) != 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008171 // Setting read only property in strict mode.
8172 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008173 isolate->factory()->NewTypeError(
8174 "strict_cannot_assign", HandleVector(&name, 1));
8175 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008176 }
8177 return *value;
8178}
8179
8180
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008181RUNTIME_FUNCTION(MaybeObject*, Runtime_Throw) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008182 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008183 ASSERT(args.length() == 1);
8184
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008185 return isolate->Throw(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008186}
8187
8188
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008189RUNTIME_FUNCTION(MaybeObject*, Runtime_ReThrow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008190 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008191 ASSERT(args.length() == 1);
8192
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008193 return isolate->ReThrow(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008194}
8195
8196
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008197RUNTIME_FUNCTION(MaybeObject*, Runtime_PromoteScheduledException) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008198 ASSERT_EQ(0, args.length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008199 return isolate->PromoteScheduledException();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008200}
8201
8202
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008203RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008204 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008205 ASSERT(args.length() == 1);
8206
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008207 Handle<Object> name(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008208 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008209 isolate->factory()->NewReferenceError("not_defined",
8210 HandleVector(&name, 1));
8211 return isolate->Throw(*reference_error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008212}
8213
8214
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008215RUNTIME_FUNCTION(MaybeObject*, Runtime_StackGuard) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00008216 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008217
8218 // First check if this is a real stack overflow.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008219 if (isolate->stack_guard()->IsStackOverflow()) {
8220 NoHandleAllocation na;
8221 return isolate->StackOverflow();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008222 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008223
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008224 return Execution::HandleStackGuardInterrupt();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008225}
8226
8227
8228// NOTE: These PrintXXX functions are defined for all builds (not just
8229// DEBUG builds) because we may want to be able to trace function
8230// calls in all modes.
8231static void PrintString(String* str) {
8232 // not uncommon to have empty strings
8233 if (str->length() > 0) {
8234 SmartPointer<char> s =
8235 str->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
8236 PrintF("%s", *s);
8237 }
8238}
8239
8240
8241static void PrintObject(Object* obj) {
8242 if (obj->IsSmi()) {
8243 PrintF("%d", Smi::cast(obj)->value());
8244 } else if (obj->IsString() || obj->IsSymbol()) {
8245 PrintString(String::cast(obj));
8246 } else if (obj->IsNumber()) {
8247 PrintF("%g", obj->Number());
8248 } else if (obj->IsFailure()) {
8249 PrintF("<failure>");
8250 } else if (obj->IsUndefined()) {
8251 PrintF("<undefined>");
8252 } else if (obj->IsNull()) {
8253 PrintF("<null>");
8254 } else if (obj->IsTrue()) {
8255 PrintF("<true>");
8256 } else if (obj->IsFalse()) {
8257 PrintF("<false>");
8258 } else {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00008259 PrintF("%p", reinterpret_cast<void*>(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008260 }
8261}
8262
8263
8264static int StackSize() {
8265 int n = 0;
8266 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
8267 return n;
8268}
8269
8270
8271static void PrintTransition(Object* result) {
8272 // indentation
8273 { const int nmax = 80;
8274 int n = StackSize();
8275 if (n <= nmax)
8276 PrintF("%4d:%*s", n, n, "");
8277 else
8278 PrintF("%4d:%*s", n, nmax, "...");
8279 }
8280
8281 if (result == NULL) {
8282 // constructor calls
8283 JavaScriptFrameIterator it;
8284 JavaScriptFrame* frame = it.frame();
8285 if (frame->IsConstructor()) PrintF("new ");
8286 // function name
8287 Object* fun = frame->function();
8288 if (fun->IsJSFunction()) {
8289 PrintObject(JSFunction::cast(fun)->shared()->name());
8290 } else {
8291 PrintObject(fun);
8292 }
8293 // function arguments
8294 // (we are intentionally only printing the actually
8295 // supplied parameters, not all parameters required)
8296 PrintF("(this=");
8297 PrintObject(frame->receiver());
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00008298 const int length = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008299 for (int i = 0; i < length; i++) {
8300 PrintF(", ");
8301 PrintObject(frame->GetParameter(i));
8302 }
8303 PrintF(") {\n");
8304
8305 } else {
8306 // function result
8307 PrintF("} -> ");
8308 PrintObject(result);
8309 PrintF("\n");
8310 }
8311}
8312
8313
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008314RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceEnter) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008315 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008316 NoHandleAllocation ha;
8317 PrintTransition(NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008318 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008319}
8320
8321
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008322RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceExit) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008323 NoHandleAllocation ha;
8324 PrintTransition(args[0]);
8325 return args[0]; // return TOS
8326}
8327
8328
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008329RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008330 NoHandleAllocation ha;
8331 ASSERT(args.length() == 1);
8332
8333#ifdef DEBUG
8334 if (args[0]->IsString()) {
8335 // If we have a string, assume it's a code "marker"
8336 // and print some interesting cpu debugging info.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008337 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008338 JavaScriptFrame* frame = it.frame();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008339 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
8340 frame->fp(), frame->sp(), frame->caller_sp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008341 } else {
8342 PrintF("DebugPrint: ");
8343 }
8344 args[0]->Print();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008345 if (args[0]->IsHeapObject()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008346 PrintF("\n");
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008347 HeapObject::cast(args[0])->map()->Print();
8348 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008349#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008350 // ShortPrint is available in release mode. Print is not.
8351 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008352#endif
8353 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00008354 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008355
8356 return args[0]; // return TOS
8357}
8358
8359
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008360RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugTrace) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008361 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008362 NoHandleAllocation ha;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008363 isolate->PrintStack();
8364 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008365}
8366
8367
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008368RUNTIME_FUNCTION(MaybeObject*, Runtime_DateCurrentTime) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008369 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00008370 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008371
8372 // According to ECMA-262, section 15.9.1, page 117, the precision of
8373 // the number in a Date object representing a particular instant in
8374 // time is milliseconds. Therefore, we floor the result of getting
8375 // the OS time.
8376 double millis = floor(OS::TimeCurrentMillis());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008377 return isolate->heap()->NumberFromDouble(millis);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008378}
8379
8380
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008381RUNTIME_FUNCTION(MaybeObject*, Runtime_DateParseString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008382 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008383 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008384
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008385 CONVERT_ARG_CHECKED(String, str, 0);
8386 FlattenString(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008387
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008388 CONVERT_ARG_CHECKED(JSArray, output, 1);
8389 RUNTIME_ASSERT(output->HasFastElements());
8390
8391 AssertNoAllocation no_allocation;
8392
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008393 FixedArray* output_array = FixedArray::cast(output->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008394 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
8395 bool result;
ager@chromium.org5ec48922009-05-05 07:25:34 +00008396 if (str->IsAsciiRepresentation()) {
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008397 result = DateParser::Parse(str->ToAsciiVector(),
8398 output_array,
8399 isolate->unicode_cache());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008400 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00008401 ASSERT(str->IsTwoByteRepresentation());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008402 result = DateParser::Parse(str->ToUC16Vector(),
8403 output_array,
8404 isolate->unicode_cache());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008405 }
8406
8407 if (result) {
8408 return *output;
8409 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008410 return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008411 }
8412}
8413
8414
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008415RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimezone) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008416 NoHandleAllocation ha;
8417 ASSERT(args.length() == 1);
8418
8419 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00008420 const char* zone = OS::LocalTimezone(x);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008421 return isolate->heap()->AllocateStringFromUtf8(CStrVector(zone));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008422}
8423
8424
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008425RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimeOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008426 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00008427 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008428
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008429 return isolate->heap()->NumberFromDouble(OS::LocalTimeOffset());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008430}
8431
8432
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008433RUNTIME_FUNCTION(MaybeObject*, Runtime_DateDaylightSavingsOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008434 NoHandleAllocation ha;
8435 ASSERT(args.length() == 1);
8436
8437 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008438 return isolate->heap()->NumberFromDouble(OS::DaylightSavingsOffset(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008439}
8440
8441
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008442RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalReceiver) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008443 ASSERT(args.length() == 1);
8444 Object* global = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008445 if (!global->IsJSGlobalObject()) return isolate->heap()->null_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008446 return JSGlobalObject::cast(global)->global_receiver();
8447}
8448
8449
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008450RUNTIME_FUNCTION(MaybeObject*, Runtime_ParseJson) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008451 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008452 ASSERT_EQ(1, args.length());
8453 CONVERT_ARG_CHECKED(String, source, 0);
8454
8455 Handle<Object> result = JsonParser::Parse(source);
8456 if (result.is_null()) {
8457 // Syntax error or stack overflow in scanner.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008458 ASSERT(isolate->has_pending_exception());
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008459 return Failure::Exception();
8460 }
8461 return *result;
8462}
8463
8464
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008465bool CodeGenerationFromStringsAllowed(Isolate* isolate,
8466 Handle<Context> context) {
8467 if (context->allow_code_gen_from_strings()->IsFalse()) {
8468 // Check with callback if set.
8469 AllowCodeGenerationFromStringsCallback callback =
8470 isolate->allow_code_gen_callback();
8471 if (callback == NULL) {
8472 // No callback set and code generation disallowed.
8473 return false;
8474 } else {
8475 // Callback set. Let it decide if code generation is allowed.
8476 VMState state(isolate, EXTERNAL);
8477 return callback(v8::Utils::ToLocal(context));
8478 }
8479 }
8480 return true;
8481}
8482
8483
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008484RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008485 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008486 ASSERT_EQ(1, args.length());
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00008487 CONVERT_ARG_CHECKED(String, source, 0);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008488
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008489 // Extract global context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008490 Handle<Context> context(isolate->context()->global_context());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008491
8492 // Check if global context allows code generation from
8493 // strings. Throw an exception if it doesn't.
8494 if (!CodeGenerationFromStringsAllowed(isolate, context)) {
8495 return isolate->Throw(*isolate->factory()->NewError(
8496 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
8497 }
8498
8499 // Compile source string in the global context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00008500 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(source,
8501 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008502 true,
8503 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00008504 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008505 Handle<JSFunction> fun =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008506 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
8507 context,
8508 NOT_TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008509 return *fun;
8510}
8511
8512
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008513static ObjectPair CompileGlobalEval(Isolate* isolate,
8514 Handle<String> source,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008515 Handle<Object> receiver,
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00008516 StrictModeFlag strict_mode) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008517 Handle<Context> context = Handle<Context>(isolate->context());
8518 Handle<Context> global_context = Handle<Context>(context->global_context());
8519
8520 // Check if global context allows code generation from
8521 // strings. Throw an exception if it doesn't.
8522 if (!CodeGenerationFromStringsAllowed(isolate, global_context)) {
8523 isolate->Throw(*isolate->factory()->NewError(
8524 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
8525 return MakePair(Failure::Exception(), NULL);
8526 }
8527
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008528 // Deal with a normal eval call with a string argument. Compile it
8529 // and return the compiled function bound in the local context.
8530 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
8531 source,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008532 Handle<Context>(isolate->context()),
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008533 context->IsGlobalContext(),
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00008534 strict_mode);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008535 if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008536 Handle<JSFunction> compiled =
8537 isolate->factory()->NewFunctionFromSharedFunctionInfo(
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008538 shared, context, NOT_TENURED);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008539 return MakePair(*compiled, *receiver);
8540}
8541
8542
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008543RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008544 ASSERT(args.length() == 4);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008545
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008546 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008547 Handle<Object> callee = args.at<Object>(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008548 Handle<Object> receiver; // Will be overwritten.
8549
8550 // Compute the calling context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008551 Handle<Context> context = Handle<Context>(isolate->context(), isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008552#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008553 // Make sure Isolate::context() agrees with the old code that traversed
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008554 // the stack frames to compute the context.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008555 StackFrameLocator locator;
8556 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008557 ASSERT(Context::cast(frame->context()) == *context);
8558#endif
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008559
8560 // Find where the 'eval' symbol is bound. It is unaliased only if
8561 // it is bound in the global context.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008562 int index = -1;
8563 PropertyAttributes attributes = ABSENT;
8564 while (true) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008565 receiver = context->Lookup(isolate->factory()->eval_symbol(),
8566 FOLLOW_PROTOTYPE_CHAIN,
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008567 &index, &attributes);
iposva@chromium.org245aa852009-02-10 00:49:54 +00008568 // Stop search when eval is found or when the global context is
8569 // reached.
8570 if (attributes != ABSENT || context->IsGlobalContext()) break;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008571 if (context->is_function_context()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008572 context = Handle<Context>(Context::cast(context->closure()->context()),
8573 isolate);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008574 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008575 context = Handle<Context>(context->previous(), isolate);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008576 }
8577 }
8578
iposva@chromium.org245aa852009-02-10 00:49:54 +00008579 // If eval could not be resolved, it has been deleted and we need to
8580 // throw a reference error.
8581 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008582 Handle<Object> name = isolate->factory()->eval_symbol();
iposva@chromium.org245aa852009-02-10 00:49:54 +00008583 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008584 isolate->factory()->NewReferenceError("not_defined",
8585 HandleVector(&name, 1));
8586 return MakePair(isolate->Throw(*reference_error), NULL);
iposva@chromium.org245aa852009-02-10 00:49:54 +00008587 }
8588
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008589 if (!context->IsGlobalContext()) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008590 // 'eval' is not bound in the global context. Just call the function
8591 // with the given arguments. This is not necessarily the global eval.
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00008592 if (receiver->IsContext() || receiver->IsJSContextExtensionObject()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008593 receiver = isolate->factory()->the_hole_value();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008594 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008595 return MakePair(*callee, *receiver);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008596 }
8597
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008598 // 'eval' is bound in the global context, but it may have been overwritten.
8599 // Compare it to the builtin 'GlobalEval' function to make sure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008600 if (*callee != isolate->global_context()->global_eval_fun() ||
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008601 !args[1]->IsString()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008602 return MakePair(*callee, isolate->heap()->the_hole_value());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008603 }
8604
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008605 ASSERT(args[3]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008606 return CompileGlobalEval(isolate,
8607 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008608 args.at<Object>(2),
8609 static_cast<StrictModeFlag>(
8610 Smi::cast(args[3])->value()));
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008611}
8612
8613
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008614RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEvalNoLookup) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008615 ASSERT(args.length() == 4);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008616
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008617 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008618 Handle<Object> callee = args.at<Object>(0);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008619
8620 // 'eval' is bound in the global context, but it may have been overwritten.
8621 // Compare it to the builtin 'GlobalEval' function to make sure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008622 if (*callee != isolate->global_context()->global_eval_fun() ||
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008623 !args[1]->IsString()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008624 return MakePair(*callee, isolate->heap()->the_hole_value());
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008625 }
8626
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008627 ASSERT(args[3]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008628 return CompileGlobalEval(isolate,
8629 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008630 args.at<Object>(2),
8631 static_cast<StrictModeFlag>(
8632 Smi::cast(args[3])->value()));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008633}
8634
8635
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008636RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNewFunctionAttributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008637 // This utility adjusts the property attributes for newly created Function
8638 // object ("new Function(...)") by changing the map.
8639 // All it does is changing the prototype property to enumerable
8640 // as specified in ECMA262, 15.3.5.2.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008641 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008642 ASSERT(args.length() == 1);
8643 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008644
8645 Handle<Map> map = func->shared()->strict_mode()
8646 ? isolate->strict_mode_function_instance_map()
8647 : isolate->function_instance_map();
8648
8649 ASSERT(func->map()->instance_type() == map->instance_type());
8650 ASSERT(func->map()->instance_size() == map->instance_size());
8651 func->set_map(*map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008652 return *func;
8653}
8654
8655
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008656RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateInNewSpace) {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008657 // Allocate a block of memory in NewSpace (filled with a filler).
8658 // Use as fallback for allocation in generated code when NewSpace
8659 // is full.
8660 ASSERT(args.length() == 1);
8661 CONVERT_ARG_CHECKED(Smi, size_smi, 0);
8662 int size = size_smi->value();
8663 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
8664 RUNTIME_ASSERT(size > 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008665 Heap* heap = isolate->heap();
8666 const int kMinFreeNewSpaceAfterGC = heap->InitialSemiSpaceSize() * 3/4;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008667 RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008668 Object* allocation;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008669 { MaybeObject* maybe_allocation = heap->new_space()->AllocateRaw(size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008670 if (maybe_allocation->ToObject(&allocation)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008671 heap->CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008672 }
8673 return maybe_allocation;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008674 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008675}
8676
8677
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008678// Push an object unto an array of objects if it is not already in the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008679// array. Returns true if the element was pushed on the stack and
8680// false otherwise.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008681RUNTIME_FUNCTION(MaybeObject*, Runtime_PushIfAbsent) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008682 ASSERT(args.length() == 2);
8683 CONVERT_CHECKED(JSArray, array, args[0]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008684 CONVERT_CHECKED(JSObject, element, args[1]);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008685 RUNTIME_ASSERT(array->HasFastElements());
8686 int length = Smi::cast(array->length())->value();
8687 FixedArray* elements = FixedArray::cast(array->elements());
8688 for (int i = 0; i < length; i++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008689 if (elements->get(i) == element) return isolate->heap()->false_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008690 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00008691 Object* obj;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008692 // Strict not needed. Used for cycle detection in Array join implementation.
8693 { MaybeObject* maybe_obj = array->SetFastElement(length, element,
8694 kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008695 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8696 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008697 return isolate->heap()->true_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008698}
8699
8700
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008701/**
8702 * A simple visitor visits every element of Array's.
8703 * The backend storage can be a fixed array for fast elements case,
8704 * or a dictionary for sparse array. Since Dictionary is a subtype
8705 * of FixedArray, the class can be used by both fast and slow cases.
8706 * The second parameter of the constructor, fast_elements, specifies
8707 * whether the storage is a FixedArray or Dictionary.
8708 *
8709 * An index limit is used to deal with the situation that a result array
8710 * length overflows 32-bit non-negative integer.
8711 */
8712class ArrayConcatVisitor {
8713 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008714 ArrayConcatVisitor(Isolate* isolate,
8715 Handle<FixedArray> storage,
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008716 bool fast_elements) :
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008717 isolate_(isolate),
8718 storage_(Handle<FixedArray>::cast(
8719 isolate->global_handles()->Create(*storage))),
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008720 index_offset_(0u),
8721 fast_elements_(fast_elements) { }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008722
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008723 ~ArrayConcatVisitor() {
8724 clear_storage();
8725 }
8726
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008727 void visit(uint32_t i, Handle<Object> elm) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008728 if (i >= JSObject::kMaxElementCount - index_offset_) return;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008729 uint32_t index = index_offset_ + i;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008730
8731 if (fast_elements_) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008732 if (index < static_cast<uint32_t>(storage_->length())) {
8733 storage_->set(index, *elm);
8734 return;
8735 }
8736 // Our initial estimate of length was foiled, possibly by
8737 // getters on the arrays increasing the length of later arrays
8738 // during iteration.
8739 // This shouldn't happen in anything but pathological cases.
8740 SetDictionaryMode(index);
8741 // Fall-through to dictionary mode.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008742 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008743 ASSERT(!fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008744 Handle<NumberDictionary> dict(NumberDictionary::cast(*storage_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008745 Handle<NumberDictionary> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008746 isolate_->factory()->DictionaryAtNumberPut(dict, index, elm);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008747 if (!result.is_identical_to(dict)) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008748 // Dictionary needed to grow.
8749 clear_storage();
8750 set_storage(*result);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008751 }
8752}
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008753
8754 void increase_index_offset(uint32_t delta) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008755 if (JSObject::kMaxElementCount - index_offset_ < delta) {
8756 index_offset_ = JSObject::kMaxElementCount;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008757 } else {
8758 index_offset_ += delta;
8759 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008760 }
8761
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008762 Handle<JSArray> ToArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008763 Handle<JSArray> array = isolate_->factory()->NewJSArray(0);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008764 Handle<Object> length =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008765 isolate_->factory()->NewNumber(static_cast<double>(index_offset_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008766 Handle<Map> map;
8767 if (fast_elements_) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008768 map = isolate_->factory()->GetFastElementsMap(Handle<Map>(array->map()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008769 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008770 map = isolate_->factory()->GetSlowElementsMap(Handle<Map>(array->map()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008771 }
8772 array->set_map(*map);
8773 array->set_length(*length);
8774 array->set_elements(*storage_);
8775 return array;
8776 }
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00008777
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008778 private:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008779 // Convert storage to dictionary mode.
8780 void SetDictionaryMode(uint32_t index) {
8781 ASSERT(fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008782 Handle<FixedArray> current_storage(*storage_);
8783 Handle<NumberDictionary> slow_storage(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008784 isolate_->factory()->NewNumberDictionary(current_storage->length()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008785 uint32_t current_length = static_cast<uint32_t>(current_storage->length());
8786 for (uint32_t i = 0; i < current_length; i++) {
8787 HandleScope loop_scope;
8788 Handle<Object> element(current_storage->get(i));
8789 if (!element->IsTheHole()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008790 Handle<NumberDictionary> new_storage =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008791 isolate_->factory()->DictionaryAtNumberPut(slow_storage, i, element);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008792 if (!new_storage.is_identical_to(slow_storage)) {
8793 slow_storage = loop_scope.CloseAndEscape(new_storage);
8794 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008795 }
8796 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008797 clear_storage();
8798 set_storage(*slow_storage);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008799 fast_elements_ = false;
8800 }
8801
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008802 inline void clear_storage() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008803 isolate_->global_handles()->Destroy(
8804 Handle<Object>::cast(storage_).location());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008805 }
8806
8807 inline void set_storage(FixedArray* storage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008808 storage_ = Handle<FixedArray>::cast(
8809 isolate_->global_handles()->Create(storage));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008810 }
8811
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008812 Isolate* isolate_;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008813 Handle<FixedArray> storage_; // Always a global handle.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008814 // Index after last seen index. Always less than or equal to
8815 // JSObject::kMaxElementCount.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008816 uint32_t index_offset_;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008817 bool fast_elements_;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008818};
8819
8820
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008821static uint32_t EstimateElementCount(Handle<JSArray> array) {
8822 uint32_t length = static_cast<uint32_t>(array->length()->Number());
8823 int element_count = 0;
8824 switch (array->GetElementsKind()) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008825 case JSObject::FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008826 // Fast elements can't have lengths that are not representable by
8827 // a 32-bit signed integer.
8828 ASSERT(static_cast<int32_t>(FixedArray::kMaxLength) >= 0);
8829 int fast_length = static_cast<int>(length);
8830 Handle<FixedArray> elements(FixedArray::cast(array->elements()));
8831 for (int i = 0; i < fast_length; i++) {
8832 if (!elements->get(i)->IsTheHole()) element_count++;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008833 }
ager@chromium.org3811b432009-10-28 14:53:37 +00008834 break;
8835 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008836 case JSObject::DICTIONARY_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008837 Handle<NumberDictionary> dictionary(
8838 NumberDictionary::cast(array->elements()));
8839 int capacity = dictionary->Capacity();
8840 for (int i = 0; i < capacity; i++) {
8841 Handle<Object> key(dictionary->KeyAt(i));
8842 if (dictionary->IsKey(*key)) {
8843 element_count++;
8844 }
8845 }
8846 break;
8847 }
8848 default:
8849 // External arrays are always dense.
8850 return length;
8851 }
8852 // As an estimate, we assume that the prototype doesn't contain any
8853 // inherited elements.
8854 return element_count;
8855}
8856
8857
8858
8859template<class ExternalArrayClass, class ElementType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008860static void IterateExternalArrayElements(Isolate* isolate,
8861 Handle<JSObject> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008862 bool elements_are_ints,
8863 bool elements_are_guaranteed_smis,
8864 ArrayConcatVisitor* visitor) {
8865 Handle<ExternalArrayClass> array(
8866 ExternalArrayClass::cast(receiver->elements()));
8867 uint32_t len = static_cast<uint32_t>(array->length());
8868
8869 ASSERT(visitor != NULL);
8870 if (elements_are_ints) {
8871 if (elements_are_guaranteed_smis) {
8872 for (uint32_t j = 0; j < len; j++) {
8873 HandleScope loop_scope;
8874 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get(j))));
8875 visitor->visit(j, e);
8876 }
8877 } else {
8878 for (uint32_t j = 0; j < len; j++) {
8879 HandleScope loop_scope;
8880 int64_t val = static_cast<int64_t>(array->get(j));
8881 if (Smi::IsValid(static_cast<intptr_t>(val))) {
8882 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
8883 visitor->visit(j, e);
8884 } else {
8885 Handle<Object> e =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008886 isolate->factory()->NewNumber(static_cast<ElementType>(val));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008887 visitor->visit(j, e);
8888 }
8889 }
8890 }
8891 } else {
8892 for (uint32_t j = 0; j < len; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008893 HandleScope loop_scope(isolate);
8894 Handle<Object> e = isolate->factory()->NewNumber(array->get(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008895 visitor->visit(j, e);
8896 }
8897 }
8898}
8899
8900
8901// Used for sorting indices in a List<uint32_t>.
8902static int compareUInt32(const uint32_t* ap, const uint32_t* bp) {
8903 uint32_t a = *ap;
8904 uint32_t b = *bp;
8905 return (a == b) ? 0 : (a < b) ? -1 : 1;
8906}
8907
8908
8909static void CollectElementIndices(Handle<JSObject> object,
8910 uint32_t range,
8911 List<uint32_t>* indices) {
8912 JSObject::ElementsKind kind = object->GetElementsKind();
8913 switch (kind) {
8914 case JSObject::FAST_ELEMENTS: {
8915 Handle<FixedArray> elements(FixedArray::cast(object->elements()));
8916 uint32_t length = static_cast<uint32_t>(elements->length());
8917 if (range < length) length = range;
8918 for (uint32_t i = 0; i < length; i++) {
8919 if (!elements->get(i)->IsTheHole()) {
8920 indices->Add(i);
8921 }
8922 }
8923 break;
8924 }
8925 case JSObject::DICTIONARY_ELEMENTS: {
8926 Handle<NumberDictionary> dict(NumberDictionary::cast(object->elements()));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008927 uint32_t capacity = dict->Capacity();
8928 for (uint32_t j = 0; j < capacity; j++) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008929 HandleScope loop_scope;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008930 Handle<Object> k(dict->KeyAt(j));
8931 if (dict->IsKey(*k)) {
8932 ASSERT(k->IsNumber());
8933 uint32_t index = static_cast<uint32_t>(k->Number());
8934 if (index < range) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008935 indices->Add(index);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008936 }
8937 }
8938 }
8939 break;
8940 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008941 default: {
8942 int dense_elements_length;
8943 switch (kind) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00008944 case JSObject::EXTERNAL_PIXEL_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008945 dense_elements_length =
8946 ExternalPixelArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008947 break;
8948 }
8949 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008950 dense_elements_length =
8951 ExternalByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008952 break;
8953 }
8954 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008955 dense_elements_length =
8956 ExternalUnsignedByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008957 break;
8958 }
8959 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008960 dense_elements_length =
8961 ExternalShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008962 break;
8963 }
8964 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008965 dense_elements_length =
8966 ExternalUnsignedShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008967 break;
8968 }
8969 case JSObject::EXTERNAL_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008970 dense_elements_length =
8971 ExternalIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008972 break;
8973 }
8974 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008975 dense_elements_length =
8976 ExternalUnsignedIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008977 break;
8978 }
8979 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008980 dense_elements_length =
8981 ExternalFloatArray::cast(object->elements())->length();
8982 break;
8983 }
8984 case JSObject::EXTERNAL_DOUBLE_ELEMENTS: {
8985 dense_elements_length =
8986 ExternalDoubleArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008987 break;
8988 }
8989 default:
8990 UNREACHABLE();
8991 dense_elements_length = 0;
8992 break;
8993 }
8994 uint32_t length = static_cast<uint32_t>(dense_elements_length);
8995 if (range <= length) {
8996 length = range;
8997 // We will add all indices, so we might as well clear it first
8998 // and avoid duplicates.
8999 indices->Clear();
9000 }
9001 for (uint32_t i = 0; i < length; i++) {
9002 indices->Add(i);
9003 }
9004 if (length == range) return; // All indices accounted for already.
9005 break;
9006 }
9007 }
9008
9009 Handle<Object> prototype(object->GetPrototype());
9010 if (prototype->IsJSObject()) {
9011 // The prototype will usually have no inherited element indices,
9012 // but we have to check.
9013 CollectElementIndices(Handle<JSObject>::cast(prototype), range, indices);
9014 }
9015}
9016
9017
9018/**
9019 * A helper function that visits elements of a JSArray in numerical
9020 * order.
9021 *
9022 * The visitor argument called for each existing element in the array
9023 * with the element index and the element's value.
9024 * Afterwards it increments the base-index of the visitor by the array
9025 * length.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009026 * Returns false if any access threw an exception, otherwise true.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009027 */
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009028static bool IterateElements(Isolate* isolate,
9029 Handle<JSArray> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009030 ArrayConcatVisitor* visitor) {
9031 uint32_t length = static_cast<uint32_t>(receiver->length()->Number());
9032 switch (receiver->GetElementsKind()) {
9033 case JSObject::FAST_ELEMENTS: {
9034 // Run through the elements FixedArray and use HasElement and GetElement
9035 // to check the prototype for missing elements.
9036 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
9037 int fast_length = static_cast<int>(length);
9038 ASSERT(fast_length <= elements->length());
9039 for (int j = 0; j < fast_length; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009040 HandleScope loop_scope(isolate);
9041 Handle<Object> element_value(elements->get(j), isolate);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009042 if (!element_value->IsTheHole()) {
9043 visitor->visit(j, element_value);
9044 } else if (receiver->HasElement(j)) {
9045 // Call GetElement on receiver, not its prototype, or getters won't
9046 // have the correct receiver.
9047 element_value = GetElement(receiver, j);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009048 if (element_value.is_null()) return false;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009049 visitor->visit(j, element_value);
9050 }
9051 }
9052 break;
9053 }
9054 case JSObject::DICTIONARY_ELEMENTS: {
9055 Handle<NumberDictionary> dict(receiver->element_dictionary());
9056 List<uint32_t> indices(dict->Capacity() / 2);
9057 // Collect all indices in the object and the prototypes less
9058 // than length. This might introduce duplicates in the indices list.
9059 CollectElementIndices(receiver, length, &indices);
9060 indices.Sort(&compareUInt32);
9061 int j = 0;
9062 int n = indices.length();
9063 while (j < n) {
9064 HandleScope loop_scope;
9065 uint32_t index = indices[j];
9066 Handle<Object> element = GetElement(receiver, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009067 if (element.is_null()) return false;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009068 visitor->visit(index, element);
9069 // Skip to next different index (i.e., omit duplicates).
9070 do {
9071 j++;
9072 } while (j < n && indices[j] == index);
9073 }
9074 break;
9075 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009076 case JSObject::EXTERNAL_PIXEL_ELEMENTS: {
9077 Handle<ExternalPixelArray> pixels(ExternalPixelArray::cast(
9078 receiver->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009079 for (uint32_t j = 0; j < length; j++) {
9080 Handle<Smi> e(Smi::FromInt(pixels->get(j)));
9081 visitor->visit(j, e);
9082 }
9083 break;
9084 }
9085 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
9086 IterateExternalArrayElements<ExternalByteArray, int8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009087 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009088 break;
9089 }
9090 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
9091 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009092 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009093 break;
9094 }
9095 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
9096 IterateExternalArrayElements<ExternalShortArray, int16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009097 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009098 break;
9099 }
9100 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
9101 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009102 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009103 break;
9104 }
9105 case JSObject::EXTERNAL_INT_ELEMENTS: {
9106 IterateExternalArrayElements<ExternalIntArray, int32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009107 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009108 break;
9109 }
9110 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
9111 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009112 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009113 break;
9114 }
9115 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
9116 IterateExternalArrayElements<ExternalFloatArray, float>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009117 isolate, receiver, false, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009118 break;
9119 }
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009120 case JSObject::EXTERNAL_DOUBLE_ELEMENTS: {
9121 IterateExternalArrayElements<ExternalDoubleArray, double>(
9122 isolate, receiver, false, false, visitor);
9123 break;
9124 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009125 default:
9126 UNREACHABLE();
9127 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009128 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009129 visitor->increase_index_offset(length);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009130 return true;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009131}
9132
9133
9134/**
9135 * Array::concat implementation.
9136 * See ECMAScript 262, 15.4.4.4.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009137 * TODO(581): Fix non-compliance for very large concatenations and update to
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009138 * following the ECMAScript 5 specification.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009139 */
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009140RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConcat) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009141 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009142 HandleScope handle_scope(isolate);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009143
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009144 CONVERT_ARG_CHECKED(JSArray, arguments, 0);
9145 int argument_count = static_cast<int>(arguments->length()->Number());
9146 RUNTIME_ASSERT(arguments->HasFastElements());
9147 Handle<FixedArray> elements(FixedArray::cast(arguments->elements()));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009148
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009149 // Pass 1: estimate the length and number of elements of the result.
9150 // The actual length can be larger if any of the arguments have getters
9151 // that mutate other arguments (but will otherwise be precise).
9152 // The number of elements is precise if there are no inherited elements.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009153
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009154 uint32_t estimate_result_length = 0;
9155 uint32_t estimate_nof_elements = 0;
9156 {
9157 for (int i = 0; i < argument_count; i++) {
9158 HandleScope loop_scope;
9159 Handle<Object> obj(elements->get(i));
9160 uint32_t length_estimate;
9161 uint32_t element_estimate;
9162 if (obj->IsJSArray()) {
9163 Handle<JSArray> array(Handle<JSArray>::cast(obj));
9164 length_estimate =
9165 static_cast<uint32_t>(array->length()->Number());
9166 element_estimate =
9167 EstimateElementCount(array);
9168 } else {
9169 length_estimate = 1;
9170 element_estimate = 1;
9171 }
9172 // Avoid overflows by capping at kMaxElementCount.
9173 if (JSObject::kMaxElementCount - estimate_result_length <
9174 length_estimate) {
9175 estimate_result_length = JSObject::kMaxElementCount;
9176 } else {
9177 estimate_result_length += length_estimate;
9178 }
9179 if (JSObject::kMaxElementCount - estimate_nof_elements <
9180 element_estimate) {
9181 estimate_nof_elements = JSObject::kMaxElementCount;
9182 } else {
9183 estimate_nof_elements += element_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009184 }
9185 }
9186 }
9187
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009188 // If estimated number of elements is more than half of length, a
9189 // fixed array (fast case) is more time and space-efficient than a
9190 // dictionary.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009191 bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009192
9193 Handle<FixedArray> storage;
9194 if (fast_case) {
9195 // The backing storage array must have non-existing elements to
9196 // preserve holes across concat operations.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009197 storage = isolate->factory()->NewFixedArrayWithHoles(
9198 estimate_result_length);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009199 } else {
9200 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
9201 uint32_t at_least_space_for = estimate_nof_elements +
9202 (estimate_nof_elements >> 2);
9203 storage = Handle<FixedArray>::cast(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009204 isolate->factory()->NewNumberDictionary(at_least_space_for));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009205 }
9206
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009207 ArrayConcatVisitor visitor(isolate, storage, fast_case);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009208
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009209 for (int i = 0; i < argument_count; i++) {
9210 Handle<Object> obj(elements->get(i));
9211 if (obj->IsJSArray()) {
9212 Handle<JSArray> array = Handle<JSArray>::cast(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009213 if (!IterateElements(isolate, array, &visitor)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009214 return Failure::Exception();
9215 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009216 } else {
9217 visitor.visit(0, obj);
9218 visitor.increase_index_offset(1);
9219 }
9220 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009221
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009222 return *visitor.ToArray();
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009223}
9224
9225
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009226// This will not allocate (flatten the string), but it may run
9227// very slowly for very deeply nested ConsStrings. For debugging use only.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009228RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009229 NoHandleAllocation ha;
9230 ASSERT(args.length() == 1);
9231
9232 CONVERT_CHECKED(String, string, args[0]);
9233 StringInputBuffer buffer(string);
9234 while (buffer.has_more()) {
9235 uint16_t character = buffer.GetNext();
9236 PrintF("%c", character);
9237 }
9238 return string;
9239}
9240
ager@chromium.org5ec48922009-05-05 07:25:34 +00009241// Moves all own elements of an object, that are below a limit, to positions
9242// starting at zero. All undefined values are placed after non-undefined values,
9243// and are followed by non-existing element. Does not change the length
9244// property.
9245// Returns the number of non-undefined elements collected.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009246RUNTIME_FUNCTION(MaybeObject*, Runtime_RemoveArrayHoles) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00009247 ASSERT(args.length() == 2);
9248 CONVERT_CHECKED(JSObject, object, args[0]);
9249 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
9250 return object->PrepareElementsForSort(limit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009251}
9252
9253
9254// Move contents of argument 0 (an array) to argument 1 (an array)
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009255RUNTIME_FUNCTION(MaybeObject*, Runtime_MoveArrayContents) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009256 ASSERT(args.length() == 2);
9257 CONVERT_CHECKED(JSArray, from, args[0]);
9258 CONVERT_CHECKED(JSArray, to, args[1]);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009259 HeapObject* new_elements = from->elements();
lrn@chromium.org303ada72010-10-27 09:33:13 +00009260 MaybeObject* maybe_new_map;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009261 if (new_elements->map() == isolate->heap()->fixed_array_map() ||
9262 new_elements->map() == isolate->heap()->fixed_cow_array_map()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009263 maybe_new_map = to->map()->GetFastElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009264 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009265 maybe_new_map = to->map()->GetSlowElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009266 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009267 Object* new_map;
9268 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009269 to->set_map(Map::cast(new_map));
9270 to->set_elements(new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009271 to->set_length(from->length());
lrn@chromium.org303ada72010-10-27 09:33:13 +00009272 Object* obj;
9273 { MaybeObject* maybe_obj = from->ResetElements();
9274 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9275 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009276 from->set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009277 return to;
9278}
9279
9280
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009281// How many elements does this object/array have?
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009282RUNTIME_FUNCTION(MaybeObject*, Runtime_EstimateNumberOfElements) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009283 ASSERT(args.length() == 1);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009284 CONVERT_CHECKED(JSObject, object, args[0]);
9285 HeapObject* elements = object->elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009286 if (elements->IsDictionary()) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009287 return Smi::FromInt(NumberDictionary::cast(elements)->NumberOfElements());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009288 } else if (object->IsJSArray()) {
9289 return JSArray::cast(object)->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009290 } else {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009291 return Smi::FromInt(FixedArray::cast(elements)->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009292 }
9293}
9294
9295
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009296RUNTIME_FUNCTION(MaybeObject*, Runtime_SwapElements) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009297 HandleScope handle_scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009298
9299 ASSERT_EQ(3, args.length());
9300
ager@chromium.orgac091b72010-05-05 07:34:42 +00009301 CONVERT_ARG_CHECKED(JSObject, object, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009302 Handle<Object> key1 = args.at<Object>(1);
9303 Handle<Object> key2 = args.at<Object>(2);
9304
9305 uint32_t index1, index2;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009306 if (!key1->ToArrayIndex(&index1)
9307 || !key2->ToArrayIndex(&index2)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009308 return isolate->ThrowIllegalOperation();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009309 }
9310
ager@chromium.orgac091b72010-05-05 07:34:42 +00009311 Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
9312 Handle<Object> tmp1 = GetElement(jsobject, index1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009313 RETURN_IF_EMPTY_HANDLE(isolate, tmp1);
ager@chromium.orgac091b72010-05-05 07:34:42 +00009314 Handle<Object> tmp2 = GetElement(jsobject, index2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009315 RETURN_IF_EMPTY_HANDLE(isolate, tmp2);
ager@chromium.orgac091b72010-05-05 07:34:42 +00009316
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009317 RETURN_IF_EMPTY_HANDLE(isolate,
9318 SetElement(jsobject, index1, tmp2, kStrictMode));
9319 RETURN_IF_EMPTY_HANDLE(isolate,
9320 SetElement(jsobject, index2, tmp1, kStrictMode));
ager@chromium.orgac091b72010-05-05 07:34:42 +00009321
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009322 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009323}
9324
9325
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009326// Returns an array that tells you where in the [0, length) interval an array
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009327// might have elements. Can either return keys (positive integers) or
9328// intervals (pair of a negative integer (-start-1) followed by a
9329// positive (length)) or undefined values.
9330// Intervals can span over some keys that are not in the object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009331RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArrayKeys) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009332 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009333 HandleScope scope(isolate);
ager@chromium.org5ec48922009-05-05 07:25:34 +00009334 CONVERT_ARG_CHECKED(JSObject, array, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009335 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009336 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009337 // Create an array and get all the keys into it, then remove all the
9338 // keys that are not integers in the range 0 to length-1.
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009339 Handle<FixedArray> keys = GetKeysInFixedArrayFor(array, INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009340 int keys_length = keys->length();
9341 for (int i = 0; i < keys_length; i++) {
9342 Object* key = keys->get(i);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009343 uint32_t index = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009344 if (!key->ToArrayIndex(&index) || index >= length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009345 // Zap invalid keys.
9346 keys->set_undefined(i);
9347 }
9348 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009349 return *isolate->factory()->NewJSArrayWithElements(keys);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009350 } else {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009351 ASSERT(array->HasFastElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009352 Handle<FixedArray> single_interval = isolate->factory()->NewFixedArray(2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009353 // -1 means start of array.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009354 single_interval->set(0, Smi::FromInt(-1));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009355 uint32_t actual_length =
9356 static_cast<uint32_t>(FixedArray::cast(array->elements())->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +00009357 uint32_t min_length = actual_length < length ? actual_length : length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009358 Handle<Object> length_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009359 isolate->factory()->NewNumber(static_cast<double>(min_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009360 single_interval->set(1, *length_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009361 return *isolate->factory()->NewJSArrayWithElements(single_interval);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009362 }
9363}
9364
9365
9366// DefineAccessor takes an optional final argument which is the
9367// property attributes (eg, DONT_ENUM, DONT_DELETE). IMPORTANT: due
9368// to the way accessors are implemented, it is set for both the getter
9369// and setter on the first call to DefineAccessor and ignored on
9370// subsequent calls.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009371RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009372 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
9373 // Compute attributes.
9374 PropertyAttributes attributes = NONE;
9375 if (args.length() == 5) {
9376 CONVERT_CHECKED(Smi, attrs, args[4]);
9377 int value = attrs->value();
9378 // Only attribute bits should be set.
9379 ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
9380 attributes = static_cast<PropertyAttributes>(value);
9381 }
9382
9383 CONVERT_CHECKED(JSObject, obj, args[0]);
9384 CONVERT_CHECKED(String, name, args[1]);
9385 CONVERT_CHECKED(Smi, flag, args[2]);
9386 CONVERT_CHECKED(JSFunction, fun, args[3]);
9387 return obj->DefineAccessor(name, flag->value() == 0, fun, attributes);
9388}
9389
9390
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009391RUNTIME_FUNCTION(MaybeObject*, Runtime_LookupAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009392 ASSERT(args.length() == 3);
9393 CONVERT_CHECKED(JSObject, obj, args[0]);
9394 CONVERT_CHECKED(String, name, args[1]);
9395 CONVERT_CHECKED(Smi, flag, args[2]);
9396 return obj->LookupAccessor(name, flag->value() == 0);
9397}
9398
9399
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009400#ifdef ENABLE_DEBUGGER_SUPPORT
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009401RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugBreak) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009402 ASSERT(args.length() == 0);
9403 return Execution::DebugBreakHelper();
9404}
9405
9406
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009407// Helper functions for wrapping and unwrapping stack frame ids.
9408static Smi* WrapFrameId(StackFrame::Id id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +00009409 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009410 return Smi::FromInt(id >> 2);
9411}
9412
9413
9414static StackFrame::Id UnwrapFrameId(Smi* wrapped) {
9415 return static_cast<StackFrame::Id>(wrapped->value() << 2);
9416}
9417
9418
9419// Adds a JavaScript function as a debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +00009420// args[0]: debug event listener function to set or null or undefined for
9421// clearing the event listener function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009422// args[1]: object supplied during callback
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009423RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDebugEventListener) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009424 ASSERT(args.length() == 2);
iposva@chromium.org245aa852009-02-10 00:49:54 +00009425 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
9426 args[0]->IsUndefined() ||
9427 args[0]->IsNull());
9428 Handle<Object> callback = args.at<Object>(0);
9429 Handle<Object> data = args.at<Object>(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009430 isolate->debugger()->SetEventListener(callback, data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009431
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009432 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009433}
9434
9435
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009436RUNTIME_FUNCTION(MaybeObject*, Runtime_Break) {
mads.s.ager31e71382008-08-13 09:32:07 +00009437 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009438 isolate->stack_guard()->DebugBreak();
9439 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009440}
9441
9442
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009443static MaybeObject* DebugLookupResultValue(Heap* heap,
9444 Object* receiver,
9445 String* name,
lrn@chromium.org303ada72010-10-27 09:33:13 +00009446 LookupResult* result,
9447 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009448 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009449 switch (result->type()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009450 case NORMAL:
9451 value = result->holder()->GetNormalizedProperty(result);
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009452 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009453 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009454 }
9455 return value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009456 case FIELD:
9457 value =
9458 JSObject::cast(
9459 result->holder())->FastPropertyAt(result->GetFieldIndex());
9460 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009461 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009462 }
9463 return value;
9464 case CONSTANT_FUNCTION:
9465 return result->GetConstantFunction();
9466 case CALLBACKS: {
9467 Object* structure = result->GetCallbackObject();
ager@chromium.orgea91cc52011-05-23 06:06:11 +00009468 if (structure->IsForeign() || structure->IsAccessorInfo()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009469 MaybeObject* maybe_value = receiver->GetPropertyWithCallback(
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00009470 receiver, structure, name, result->holder());
lrn@chromium.org303ada72010-10-27 09:33:13 +00009471 if (!maybe_value->ToObject(&value)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009472 if (maybe_value->IsRetryAfterGC()) return maybe_value;
lrn@chromium.org303ada72010-10-27 09:33:13 +00009473 ASSERT(maybe_value->IsException());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009474 maybe_value = heap->isolate()->pending_exception();
9475 heap->isolate()->clear_pending_exception();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009476 if (caught_exception != NULL) {
9477 *caught_exception = true;
9478 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009479 return maybe_value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009480 }
9481 return value;
9482 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009483 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009484 }
9485 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009486 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009487 case MAP_TRANSITION:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00009488 case EXTERNAL_ARRAY_TRANSITION:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009489 case CONSTANT_TRANSITION:
9490 case NULL_DESCRIPTOR:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009491 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009492 default:
9493 UNREACHABLE();
9494 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009495 UNREACHABLE();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009496 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009497}
9498
9499
ager@chromium.org32912102009-01-16 10:38:43 +00009500// Get debugger related details for an object property.
9501// args[0]: object holding property
9502// args[1]: name of the property
9503//
9504// The array returned contains the following information:
9505// 0: Property value
9506// 1: Property details
9507// 2: Property value is exception
9508// 3: Getter function if defined
9509// 4: Setter function if defined
9510// Items 2-4 are only filled if the property has either a getter or a setter
9511// defined through __defineGetter__ and/or __defineSetter__.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009512RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPropertyDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009513 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009514
9515 ASSERT(args.length() == 2);
9516
9517 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9518 CONVERT_ARG_CHECKED(String, name, 1);
9519
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00009520 // Make sure to set the current context to the context before the debugger was
9521 // entered (if the debugger is entered). The reason for switching context here
9522 // is that for some property lookups (accessors and interceptors) callbacks
9523 // into the embedding application can occour, and the embedding application
9524 // could have the assumption that its own global context is the current
9525 // context and not some internal debugger context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009526 SaveContext save(isolate);
9527 if (isolate->debug()->InDebugger()) {
9528 isolate->set_context(*isolate->debug()->debugger_entry()->GetContext());
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00009529 }
9530
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009531 // Skip the global proxy as it has no properties and always delegates to the
9532 // real global object.
9533 if (obj->IsJSGlobalProxy()) {
9534 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
9535 }
9536
9537
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009538 // Check if the name is trivially convertible to an index and get the element
9539 // if so.
9540 uint32_t index;
9541 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009542 Handle<FixedArray> details = isolate->factory()->NewFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009543 Object* element_or_char;
9544 { MaybeObject* maybe_element_or_char =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009545 Runtime::GetElementOrCharAt(isolate, obj, index);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009546 if (!maybe_element_or_char->ToObject(&element_or_char)) {
9547 return maybe_element_or_char;
9548 }
9549 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00009550 details->set(0, element_or_char);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009551 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009552 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009553 }
9554
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009555 // Find the number of objects making up this.
9556 int length = LocalPrototypeChainLength(*obj);
9557
9558 // Try local lookup on each of the objects.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009559 Handle<JSObject> jsproto = obj;
9560 for (int i = 0; i < length; i++) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009561 LookupResult result;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009562 jsproto->LocalLookup(*name, &result);
9563 if (result.IsProperty()) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009564 // LookupResult is not GC safe as it holds raw object pointers.
9565 // GC can happen later in this code so put the required fields into
9566 // local variables using handles when required for later use.
9567 PropertyType result_type = result.type();
9568 Handle<Object> result_callback_obj;
9569 if (result_type == CALLBACKS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009570 result_callback_obj = Handle<Object>(result.GetCallbackObject(),
9571 isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009572 }
9573 Smi* property_details = result.GetPropertyDetails().AsSmi();
9574 // DebugLookupResultValue can cause GC so details from LookupResult needs
9575 // to be copied to handles before this.
9576 bool caught_exception = false;
lrn@chromium.org303ada72010-10-27 09:33:13 +00009577 Object* raw_value;
9578 { MaybeObject* maybe_raw_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009579 DebugLookupResultValue(isolate->heap(), *obj, *name,
9580 &result, &caught_exception);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009581 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
9582 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009583 Handle<Object> value(raw_value, isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009584
9585 // If the callback object is a fixed array then it contains JavaScript
9586 // getter and/or setter.
9587 bool hasJavaScriptAccessors = result_type == CALLBACKS &&
9588 result_callback_obj->IsFixedArray();
9589 Handle<FixedArray> details =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009590 isolate->factory()->NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009591 details->set(0, *value);
9592 details->set(1, property_details);
9593 if (hasJavaScriptAccessors) {
9594 details->set(2,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009595 caught_exception ? isolate->heap()->true_value()
9596 : isolate->heap()->false_value());
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009597 details->set(3, FixedArray::cast(*result_callback_obj)->get(0));
9598 details->set(4, FixedArray::cast(*result_callback_obj)->get(1));
9599 }
9600
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009601 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009602 }
9603 if (i < length - 1) {
9604 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
9605 }
9606 }
9607
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009608 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009609}
9610
9611
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009612RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetProperty) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009613 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009614
9615 ASSERT(args.length() == 2);
9616
9617 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9618 CONVERT_ARG_CHECKED(String, name, 1);
9619
9620 LookupResult result;
9621 obj->Lookup(*name, &result);
9622 if (result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009623 return DebugLookupResultValue(isolate->heap(), *obj, *name, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009624 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009625 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009626}
9627
9628
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009629// Return the property type calculated from the property details.
9630// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009631RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyTypeFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009632 ASSERT(args.length() == 1);
9633 CONVERT_CHECKED(Smi, details, args[0]);
9634 PropertyType type = PropertyDetails(details).type();
9635 return Smi::FromInt(static_cast<int>(type));
9636}
9637
9638
9639// Return the property attribute calculated from the property details.
9640// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009641RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyAttributesFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009642 ASSERT(args.length() == 1);
9643 CONVERT_CHECKED(Smi, details, args[0]);
9644 PropertyAttributes attributes = PropertyDetails(details).attributes();
9645 return Smi::FromInt(static_cast<int>(attributes));
9646}
9647
9648
9649// Return the property insertion index calculated from the property details.
9650// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009651RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyIndexFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009652 ASSERT(args.length() == 1);
9653 CONVERT_CHECKED(Smi, details, args[0]);
9654 int index = PropertyDetails(details).index();
9655 return Smi::FromInt(index);
9656}
9657
9658
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009659// Return property value from named interceptor.
9660// args[0]: object
9661// args[1]: property name
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009662RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugNamedInterceptorPropertyValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009663 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009664 ASSERT(args.length() == 2);
9665 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9666 RUNTIME_ASSERT(obj->HasNamedInterceptor());
9667 CONVERT_ARG_CHECKED(String, name, 1);
9668
9669 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009670 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009671}
9672
9673
9674// Return element value from indexed interceptor.
9675// args[0]: object
9676// args[1]: index
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009677RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugIndexedInterceptorElementValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009678 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009679 ASSERT(args.length() == 2);
9680 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9681 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
9682 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
9683
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009684 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009685}
9686
9687
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009688RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckExecutionState) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009689 ASSERT(args.length() >= 1);
9690 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +00009691 // Check that the break id is valid.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009692 if (isolate->debug()->break_id() == 0 ||
9693 break_id != isolate->debug()->break_id()) {
9694 return isolate->Throw(
9695 isolate->heap()->illegal_execution_state_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009696 }
9697
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009698 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009699}
9700
9701
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009702RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009703 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009704 ASSERT(args.length() == 1);
9705
9706 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009707 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009708 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
9709 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +00009710 if (!maybe_result->ToObject(&result)) return maybe_result;
9711 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009712
9713 // Count all frames which are relevant to debugging stack trace.
9714 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009715 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00009716 if (id == StackFrame::NO_ID) {
9717 // If there is no JavaScript stack frame count is 0.
9718 return Smi::FromInt(0);
9719 }
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009720 for (JavaScriptFrameIterator it(isolate, id); !it.done(); it.Advance()) n++;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009721 return Smi::FromInt(n);
9722}
9723
9724
9725static const int kFrameDetailsFrameIdIndex = 0;
9726static const int kFrameDetailsReceiverIndex = 1;
9727static const int kFrameDetailsFunctionIndex = 2;
9728static const int kFrameDetailsArgumentCountIndex = 3;
9729static const int kFrameDetailsLocalCountIndex = 4;
9730static const int kFrameDetailsSourcePositionIndex = 5;
9731static const int kFrameDetailsConstructCallIndex = 6;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009732static const int kFrameDetailsAtReturnIndex = 7;
9733static const int kFrameDetailsDebuggerFrameIndex = 8;
9734static const int kFrameDetailsFirstDynamicIndex = 9;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009735
9736// Return an array with frame details
9737// args[0]: number: break id
9738// args[1]: number: frame index
9739//
9740// The array returned contains the following information:
9741// 0: Frame id
9742// 1: Receiver
9743// 2: Function
9744// 3: Argument count
9745// 4: Local count
9746// 5: Source position
9747// 6: Constructor call
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009748// 7: Is at return
9749// 8: Debugger frame
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009750// Arguments name, value
9751// Locals name, value
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009752// Return value if any
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009753RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009754 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009755 ASSERT(args.length() == 2);
9756
9757 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009758 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009759 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
9760 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +00009761 if (!maybe_check->ToObject(&check)) return maybe_check;
9762 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009763 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009764 Heap* heap = isolate->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009765
9766 // Find the relevant frame with the requested index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009767 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00009768 if (id == StackFrame::NO_ID) {
9769 // If there are no JavaScript stack frames return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009770 return heap->undefined_value();
ager@chromium.org8bb60582008-12-11 12:02:20 +00009771 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009772 int count = 0;
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009773 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009774 for (; !it.done(); it.Advance()) {
9775 if (count == index) break;
9776 count++;
9777 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009778 if (it.done()) return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009779
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009780 bool is_optimized_frame =
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009781 it.frame()->LookupCode()->kind() == Code::OPTIMIZED_FUNCTION;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009782
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009783 // Traverse the saved contexts chain to find the active context for the
9784 // selected frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009785 SaveContext* save = isolate->save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009786 while (save != NULL && !save->below(it.frame())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009787 save = save->prev();
9788 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009789 ASSERT(save != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009790
9791 // Get the frame id.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009792 Handle<Object> frame_id(WrapFrameId(it.frame()->id()), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009793
9794 // Find source position.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009795 int position =
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009796 it.frame()->LookupCode()->SourcePosition(it.frame()->pc());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009797
9798 // Check for constructor frame.
9799 bool constructor = it.frame()->IsConstructor();
9800
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009801 // Get scope info and read from it for local variable information.
9802 Handle<JSFunction> function(JSFunction::cast(it.frame()->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +00009803 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009804 ScopeInfo<> info(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009805
9806 // Get the context.
9807 Handle<Context> context(Context::cast(it.frame()->context()));
9808
9809 // Get the locals names and values into a temporary array.
9810 //
9811 // TODO(1240907): Hide compiler-introduced stack variables
9812 // (e.g. .result)? For users of the debugger, they will probably be
9813 // confusing.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009814 Handle<FixedArray> locals =
9815 isolate->factory()->NewFixedArray(info.NumberOfLocals() * 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009816
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009817 // Fill in the names of the locals.
9818 for (int i = 0; i < info.NumberOfLocals(); i++) {
9819 locals->set(i * 2, *info.LocalName(i));
9820 }
9821
9822 // Fill in the values of the locals.
9823 for (int i = 0; i < info.NumberOfLocals(); i++) {
9824 if (is_optimized_frame) {
9825 // If we are inspecting an optimized frame use undefined as the
9826 // value for all locals.
9827 //
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009828 // TODO(1140): We should be able to get the correct values
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009829 // for locals in optimized frames.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009830 locals->set(i * 2 + 1, isolate->heap()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009831 } else if (i < info.number_of_stack_slots()) {
9832 // Get the value from the stack.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009833 locals->set(i * 2 + 1, it.frame()->GetExpression(i));
9834 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009835 // Traverse the context chain to the function context as all local
9836 // variables stored in the context will be on the function context.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009837 Handle<String> name = info.LocalName(i);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009838 while (!context->is_function_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009839 context = Handle<Context>(context->previous());
9840 }
9841 ASSERT(context->is_function_context());
9842 locals->set(i * 2 + 1,
ager@chromium.orgb5737492010-07-15 09:29:43 +00009843 context->get(scope_info->ContextSlotIndex(*name, NULL)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009844 }
9845 }
9846
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009847 // Check whether this frame is positioned at return. If not top
9848 // frame or if the frame is optimized it cannot be at a return.
9849 bool at_return = false;
9850 if (!is_optimized_frame && index == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009851 at_return = isolate->debug()->IsBreakAtReturn(it.frame());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009852 }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009853
9854 // If positioned just before return find the value to be returned and add it
9855 // to the frame information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009856 Handle<Object> return_value = isolate->factory()->undefined_value();
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009857 if (at_return) {
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009858 StackFrameIterator it2(isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009859 Address internal_frame_sp = NULL;
9860 while (!it2.done()) {
9861 if (it2.frame()->is_internal()) {
9862 internal_frame_sp = it2.frame()->sp();
9863 } else {
9864 if (it2.frame()->is_java_script()) {
9865 if (it2.frame()->id() == it.frame()->id()) {
9866 // The internal frame just before the JavaScript frame contains the
9867 // value to return on top. A debug break at return will create an
9868 // internal frame to store the return value (eax/rax/r0) before
9869 // entering the debug break exit frame.
9870 if (internal_frame_sp != NULL) {
9871 return_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009872 Handle<Object>(Memory::Object_at(internal_frame_sp),
9873 isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009874 break;
9875 }
9876 }
9877 }
9878
9879 // Indicate that the previous frame was not an internal frame.
9880 internal_frame_sp = NULL;
9881 }
9882 it2.Advance();
9883 }
9884 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009885
9886 // Now advance to the arguments adapter frame (if any). It contains all
9887 // the provided parameters whereas the function frame always have the number
9888 // of arguments matching the functions parameters. The rest of the
9889 // information (except for what is collected above) is the same.
9890 it.AdvanceToArgumentsFrame();
9891
9892 // Find the number of arguments to fill. At least fill the number of
9893 // parameters for the function and fill more if more parameters are provided.
9894 int argument_count = info.number_of_parameters();
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009895 if (argument_count < it.frame()->ComputeParametersCount()) {
9896 argument_count = it.frame()->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009897 }
9898
9899 // Calculate the size of the result.
9900 int details_size = kFrameDetailsFirstDynamicIndex +
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009901 2 * (argument_count + info.NumberOfLocals()) +
9902 (at_return ? 1 : 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009903 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009904
9905 // Add the frame id.
9906 details->set(kFrameDetailsFrameIdIndex, *frame_id);
9907
9908 // Add the function (same as in function frame).
9909 details->set(kFrameDetailsFunctionIndex, it.frame()->function());
9910
9911 // Add the arguments count.
9912 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
9913
9914 // Add the locals count
9915 details->set(kFrameDetailsLocalCountIndex,
9916 Smi::FromInt(info.NumberOfLocals()));
9917
9918 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +00009919 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009920 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
9921 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009922 details->set(kFrameDetailsSourcePositionIndex, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009923 }
9924
9925 // Add the constructor information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009926 details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(constructor));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009927
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009928 // Add the at return information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009929 details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(at_return));
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009930
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009931 // Add information on whether this frame is invoked in the debugger context.
9932 details->set(kFrameDetailsDebuggerFrameIndex,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009933 heap->ToBoolean(*save->context() ==
9934 *isolate->debug()->debug_context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009935
9936 // Fill the dynamic part.
9937 int details_index = kFrameDetailsFirstDynamicIndex;
9938
9939 // Add arguments name and value.
9940 for (int i = 0; i < argument_count; i++) {
9941 // Name of the argument.
9942 if (i < info.number_of_parameters()) {
9943 details->set(details_index++, *info.parameter_name(i));
9944 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009945 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009946 }
9947
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009948 // Parameter value. If we are inspecting an optimized frame, use
9949 // undefined as the value.
9950 //
9951 // TODO(3141533): We should be able to get the actual parameter
9952 // value for optimized frames.
9953 if (!is_optimized_frame &&
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009954 (i < it.frame()->ComputeParametersCount())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009955 details->set(details_index++, it.frame()->GetParameter(i));
9956 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009957 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009958 }
9959 }
9960
9961 // Add locals name and value from the temporary copy from the function frame.
9962 for (int i = 0; i < info.NumberOfLocals() * 2; i++) {
9963 details->set(details_index++, locals->get(i));
9964 }
9965
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009966 // Add the value being returned.
9967 if (at_return) {
9968 details->set(details_index++, *return_value);
9969 }
9970
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009971 // Add the receiver (same as in function frame).
9972 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
9973 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009974 Handle<Object> receiver(it.frame()->receiver(), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009975 if (!receiver->IsJSObject()) {
9976 // If the receiver is NOT a JSObject we have hit an optimization
9977 // where a value object is not converted into a wrapped JS objects.
9978 // To hide this optimization from the debugger, we wrap the receiver
9979 // by creating correct wrapper object based on the calling frame's
9980 // global context.
9981 it.Advance();
9982 Handle<Context> calling_frames_global_context(
9983 Context::cast(Context::cast(it.frame()->context())->global_context()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009984 receiver =
9985 isolate->factory()->ToObject(receiver, calling_frames_global_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009986 }
9987 details->set(kFrameDetailsReceiverIndex, *receiver);
9988
9989 ASSERT_EQ(details_size, details_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009990 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009991}
9992
9993
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009994// Copy all the context locals into an object used to materialize a scope.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009995static bool CopyContextLocalsToScopeObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009996 Isolate* isolate,
ager@chromium.orgb5737492010-07-15 09:29:43 +00009997 Handle<SerializedScopeInfo> serialized_scope_info,
9998 ScopeInfo<>& scope_info,
9999 Handle<Context> context,
10000 Handle<JSObject> scope_object) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010001 // Fill all context locals to the context extension.
10002 for (int i = Context::MIN_CONTEXT_SLOTS;
10003 i < scope_info.number_of_context_slots();
10004 i++) {
ager@chromium.orgb5737492010-07-15 09:29:43 +000010005 int context_index = serialized_scope_info->ContextSlotIndex(
10006 *scope_info.context_slot_name(i), NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010007
10008 // Don't include the arguments shadow (.arguments) context variable.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010009 if (*scope_info.context_slot_name(i) !=
10010 isolate->heap()->arguments_shadow_symbol()) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010011 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010012 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010013 SetProperty(scope_object,
10014 scope_info.context_slot_name(i),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010015 Handle<Object>(context->get(context_index), isolate),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010016 NONE,
10017 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010018 false);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010019 }
10020 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010021
10022 return true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010023}
10024
10025
10026// Create a plain JSObject which materializes the local scope for the specified
10027// frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010028static Handle<JSObject> MaterializeLocalScope(Isolate* isolate,
10029 JavaScriptFrame* frame) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010030 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010031 Handle<SharedFunctionInfo> shared(function->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +000010032 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
10033 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010034
10035 // Allocate and initialize a JSObject with all the arguments, stack locals
10036 // heap locals and extension properties of the debugged function.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010037 Handle<JSObject> local_scope =
10038 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010039
10040 // First fill all parameters.
10041 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010042 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010043 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010044 SetProperty(local_scope,
10045 scope_info.parameter_name(i),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010046 Handle<Object>(frame->GetParameter(i), isolate),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010047 NONE,
10048 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010049 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010050 }
10051
10052 // Second fill all stack locals.
10053 for (int i = 0; i < scope_info.number_of_stack_slots(); i++) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010054 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010055 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010056 SetProperty(local_scope,
10057 scope_info.stack_slot_name(i),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010058 Handle<Object>(frame->GetExpression(i), isolate),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010059 NONE,
10060 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010061 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010062 }
10063
10064 // Third fill all context locals.
10065 Handle<Context> frame_context(Context::cast(frame->context()));
10066 Handle<Context> function_context(frame_context->fcontext());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010067 if (!CopyContextLocalsToScopeObject(isolate,
10068 serialized_scope_info, scope_info,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010069 function_context, local_scope)) {
10070 return Handle<JSObject>();
10071 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010072
10073 // Finally copy any properties from the function context extension. This will
10074 // be variables introduced by eval.
10075 if (function_context->closure() == *function) {
10076 if (function_context->has_extension() &&
10077 !function_context->IsGlobalContext()) {
10078 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010079 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010080 for (int i = 0; i < keys->length(); i++) {
10081 // Names of variables introduced by eval are strings.
10082 ASSERT(keys->get(i)->IsString());
10083 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010084 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010085 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010086 SetProperty(local_scope,
10087 key,
10088 GetProperty(ext, key),
10089 NONE,
10090 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010091 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010092 }
10093 }
10094 }
10095 return local_scope;
10096}
10097
10098
10099// Create a plain JSObject which materializes the closure content for the
10100// context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010101static Handle<JSObject> MaterializeClosure(Isolate* isolate,
10102 Handle<Context> context) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010103 ASSERT(context->is_function_context());
10104
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010105 Handle<SharedFunctionInfo> shared(context->closure()->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +000010106 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
10107 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010108
10109 // Allocate and initialize a JSObject with all the content of theis function
10110 // closure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010111 Handle<JSObject> closure_scope =
10112 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010113
10114 // Check whether the arguments shadow object exists.
10115 int arguments_shadow_index =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010116 shared->scope_info()->ContextSlotIndex(
10117 isolate->heap()->arguments_shadow_symbol(), NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010118 if (arguments_shadow_index >= 0) {
10119 // In this case all the arguments are available in the arguments shadow
10120 // object.
10121 Handle<JSObject> arguments_shadow(
10122 JSObject::cast(context->get(arguments_shadow_index)));
10123 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000010124 // We don't expect exception-throwing getters on the arguments shadow.
10125 Object* element = arguments_shadow->GetElement(i)->ToObjectUnchecked();
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010126 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010127 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010128 SetProperty(closure_scope,
10129 scope_info.parameter_name(i),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010130 Handle<Object>(element, isolate),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010131 NONE,
10132 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010133 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010134 }
10135 }
10136
10137 // Fill all context locals to the context extension.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010138 if (!CopyContextLocalsToScopeObject(isolate,
10139 serialized_scope_info, scope_info,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010140 context, closure_scope)) {
10141 return Handle<JSObject>();
10142 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010143
10144 // Finally copy any properties from the function context extension. This will
10145 // be variables introduced by eval.
10146 if (context->has_extension()) {
10147 Handle<JSObject> ext(JSObject::cast(context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010148 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010149 for (int i = 0; i < keys->length(); i++) {
10150 // Names of variables introduced by eval are strings.
10151 ASSERT(keys->get(i)->IsString());
10152 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010153 RETURN_IF_EMPTY_HANDLE_VALUE(
10154 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010155 SetProperty(closure_scope,
10156 key,
10157 GetProperty(ext, key),
10158 NONE,
10159 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010160 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010161 }
10162 }
10163
10164 return closure_scope;
10165}
10166
10167
10168// Iterate over the actual scopes visible from a stack frame. All scopes are
10169// backed by an actual context except the local scope, which is inserted
10170// "artifically" in the context chain.
10171class ScopeIterator {
10172 public:
10173 enum ScopeType {
10174 ScopeTypeGlobal = 0,
10175 ScopeTypeLocal,
10176 ScopeTypeWith,
ager@chromium.orga1645e22009-09-09 19:27:10 +000010177 ScopeTypeClosure,
10178 // Every catch block contains an implicit with block (its parameter is
10179 // a JSContextExtensionObject) that extends current scope with a variable
10180 // holding exception object. Such with blocks are treated as scopes of their
10181 // own type.
10182 ScopeTypeCatch
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010183 };
10184
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010185 ScopeIterator(Isolate* isolate, JavaScriptFrame* frame)
10186 : isolate_(isolate),
10187 frame_(frame),
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010188 function_(JSFunction::cast(frame->function())),
10189 context_(Context::cast(frame->context())),
10190 local_done_(false),
10191 at_local_(false) {
10192
10193 // Check whether the first scope is actually a local scope.
10194 if (context_->IsGlobalContext()) {
10195 // If there is a stack slot for .result then this local scope has been
10196 // created for evaluating top level code and it is not a real local scope.
10197 // Checking for the existence of .result seems fragile, but the scope info
10198 // saved with the code object does not otherwise have that information.
ager@chromium.orgb5737492010-07-15 09:29:43 +000010199 int index = function_->shared()->scope_info()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010200 StackSlotIndex(isolate_->heap()->result_symbol());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010201 at_local_ = index < 0;
10202 } else if (context_->is_function_context()) {
10203 at_local_ = true;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000010204 } else if (context_->closure() != *function_) {
10205 // The context_ is a with block from the outer function.
10206 ASSERT(context_->has_extension());
10207 at_local_ = true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010208 }
10209 }
10210
10211 // More scopes?
10212 bool Done() { return context_.is_null(); }
10213
10214 // Move to the next scope.
10215 void Next() {
10216 // If at a local scope mark the local scope as passed.
10217 if (at_local_) {
10218 at_local_ = false;
10219 local_done_ = true;
10220
10221 // If the current context is not associated with the local scope the
10222 // current context is the next real scope, so don't move to the next
10223 // context in this case.
10224 if (context_->closure() != *function_) {
10225 return;
10226 }
10227 }
10228
10229 // The global scope is always the last in the chain.
10230 if (context_->IsGlobalContext()) {
10231 context_ = Handle<Context>();
10232 return;
10233 }
10234
10235 // Move to the next context.
10236 if (context_->is_function_context()) {
10237 context_ = Handle<Context>(Context::cast(context_->closure()->context()));
10238 } else {
10239 context_ = Handle<Context>(context_->previous());
10240 }
10241
10242 // If passing the local scope indicate that the current scope is now the
10243 // local scope.
10244 if (!local_done_ &&
10245 (context_->IsGlobalContext() || (context_->is_function_context()))) {
10246 at_local_ = true;
10247 }
10248 }
10249
10250 // Return the type of the current scope.
10251 int Type() {
10252 if (at_local_) {
10253 return ScopeTypeLocal;
10254 }
10255 if (context_->IsGlobalContext()) {
10256 ASSERT(context_->global()->IsGlobalObject());
10257 return ScopeTypeGlobal;
10258 }
10259 if (context_->is_function_context()) {
10260 return ScopeTypeClosure;
10261 }
10262 ASSERT(context_->has_extension());
ager@chromium.orga1645e22009-09-09 19:27:10 +000010263 // Current scope is either an explicit with statement or a with statement
10264 // implicitely generated for a catch block.
10265 // If the extension object here is a JSContextExtensionObject then
10266 // current with statement is one frome a catch block otherwise it's a
10267 // regular with statement.
10268 if (context_->extension()->IsJSContextExtensionObject()) {
10269 return ScopeTypeCatch;
10270 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010271 return ScopeTypeWith;
10272 }
10273
10274 // Return the JavaScript object with the content of the current scope.
10275 Handle<JSObject> ScopeObject() {
10276 switch (Type()) {
10277 case ScopeIterator::ScopeTypeGlobal:
10278 return Handle<JSObject>(CurrentContext()->global());
10279 break;
10280 case ScopeIterator::ScopeTypeLocal:
10281 // Materialize the content of the local scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010282 return MaterializeLocalScope(isolate_, frame_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010283 break;
10284 case ScopeIterator::ScopeTypeWith:
ager@chromium.orga1645e22009-09-09 19:27:10 +000010285 case ScopeIterator::ScopeTypeCatch:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010286 // Return the with object.
10287 return Handle<JSObject>(CurrentContext()->extension());
10288 break;
10289 case ScopeIterator::ScopeTypeClosure:
10290 // Materialize the content of the closure scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010291 return MaterializeClosure(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010292 break;
10293 }
10294 UNREACHABLE();
10295 return Handle<JSObject>();
10296 }
10297
10298 // Return the context for this scope. For the local context there might not
10299 // be an actual context.
10300 Handle<Context> CurrentContext() {
10301 if (at_local_ && context_->closure() != *function_) {
10302 return Handle<Context>();
10303 }
10304 return context_;
10305 }
10306
10307#ifdef DEBUG
10308 // Debug print of the content of the current scope.
10309 void DebugPrint() {
10310 switch (Type()) {
10311 case ScopeIterator::ScopeTypeGlobal:
10312 PrintF("Global:\n");
10313 CurrentContext()->Print();
10314 break;
10315
10316 case ScopeIterator::ScopeTypeLocal: {
10317 PrintF("Local:\n");
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010318 ScopeInfo<> scope_info(function_->shared()->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010319 scope_info.Print();
10320 if (!CurrentContext().is_null()) {
10321 CurrentContext()->Print();
10322 if (CurrentContext()->has_extension()) {
10323 Handle<JSObject> extension =
10324 Handle<JSObject>(CurrentContext()->extension());
10325 if (extension->IsJSContextExtensionObject()) {
10326 extension->Print();
10327 }
10328 }
10329 }
10330 break;
10331 }
10332
10333 case ScopeIterator::ScopeTypeWith: {
10334 PrintF("With:\n");
10335 Handle<JSObject> extension =
10336 Handle<JSObject>(CurrentContext()->extension());
10337 extension->Print();
10338 break;
10339 }
10340
ager@chromium.orga1645e22009-09-09 19:27:10 +000010341 case ScopeIterator::ScopeTypeCatch: {
10342 PrintF("Catch:\n");
10343 Handle<JSObject> extension =
10344 Handle<JSObject>(CurrentContext()->extension());
10345 extension->Print();
10346 break;
10347 }
10348
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010349 case ScopeIterator::ScopeTypeClosure: {
10350 PrintF("Closure:\n");
10351 CurrentContext()->Print();
10352 if (CurrentContext()->has_extension()) {
10353 Handle<JSObject> extension =
10354 Handle<JSObject>(CurrentContext()->extension());
10355 if (extension->IsJSContextExtensionObject()) {
10356 extension->Print();
10357 }
10358 }
10359 break;
10360 }
10361
10362 default:
10363 UNREACHABLE();
10364 }
10365 PrintF("\n");
10366 }
10367#endif
10368
10369 private:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010370 Isolate* isolate_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010371 JavaScriptFrame* frame_;
10372 Handle<JSFunction> function_;
10373 Handle<Context> context_;
10374 bool local_done_;
10375 bool at_local_;
10376
10377 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
10378};
10379
10380
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010381RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010382 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010383 ASSERT(args.length() == 2);
10384
10385 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010386 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010387 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10388 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010389 if (!maybe_check->ToObject(&check)) return maybe_check;
10390 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010391 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
10392
10393 // Get the frame where the debugging is performed.
10394 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010395 JavaScriptFrameIterator it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010396 JavaScriptFrame* frame = it.frame();
10397
10398 // Count the visible scopes.
10399 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010400 for (ScopeIterator it(isolate, frame); !it.Done(); it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010401 n++;
10402 }
10403
10404 return Smi::FromInt(n);
10405}
10406
10407
10408static const int kScopeDetailsTypeIndex = 0;
10409static const int kScopeDetailsObjectIndex = 1;
10410static const int kScopeDetailsSize = 2;
10411
10412// Return an array with scope details
10413// args[0]: number: break id
10414// args[1]: number: frame index
10415// args[2]: number: scope index
10416//
10417// The array returned contains the following information:
10418// 0: Scope type
10419// 1: Scope object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010420RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010421 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010422 ASSERT(args.length() == 3);
10423
10424 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010425 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010426 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10427 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010428 if (!maybe_check->ToObject(&check)) return maybe_check;
10429 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010430 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
10431 CONVERT_NUMBER_CHECKED(int, index, Int32, args[2]);
10432
10433 // Get the frame where the debugging is performed.
10434 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010435 JavaScriptFrameIterator frame_it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010436 JavaScriptFrame* frame = frame_it.frame();
10437
10438 // Find the requested scope.
10439 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010440 ScopeIterator it(isolate, frame);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010441 for (; !it.Done() && n < index; it.Next()) {
10442 n++;
10443 }
10444 if (it.Done()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010445 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010446 }
10447
10448 // Calculate the size of the result.
10449 int details_size = kScopeDetailsSize;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010450 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010451
10452 // Fill in scope details.
10453 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010454 Handle<JSObject> scope_object = it.ScopeObject();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010455 RETURN_IF_EMPTY_HANDLE(isolate, scope_object);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010456 details->set(kScopeDetailsObjectIndex, *scope_object);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010457
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010458 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010459}
10460
10461
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010462RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrintScopes) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010463 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010464 ASSERT(args.length() == 0);
10465
10466#ifdef DEBUG
10467 // Print the scopes for the top frame.
10468 StackFrameLocator locator;
10469 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010470 for (ScopeIterator it(isolate, frame); !it.Done(); it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010471 it.DebugPrint();
10472 }
10473#endif
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010474 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010475}
10476
10477
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010478RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010479 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010480 ASSERT(args.length() == 1);
10481
10482 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010483 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010484 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
10485 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010486 if (!maybe_result->ToObject(&result)) return maybe_result;
10487 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010488
10489 // Count all archived V8 threads.
10490 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010491 for (ThreadState* thread =
10492 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010493 thread != NULL;
10494 thread = thread->Next()) {
10495 n++;
10496 }
10497
10498 // Total number of threads is current thread and archived threads.
10499 return Smi::FromInt(n + 1);
10500}
10501
10502
10503static const int kThreadDetailsCurrentThreadIndex = 0;
10504static const int kThreadDetailsThreadIdIndex = 1;
10505static const int kThreadDetailsSize = 2;
10506
10507// Return an array with thread details
10508// args[0]: number: break id
10509// args[1]: number: thread index
10510//
10511// The array returned contains the following information:
10512// 0: Is current thread?
10513// 1: Thread id
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010514RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010515 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010516 ASSERT(args.length() == 2);
10517
10518 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010519 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010520 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10521 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010522 if (!maybe_check->ToObject(&check)) return maybe_check;
10523 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010524 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
10525
10526 // Allocate array for result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010527 Handle<FixedArray> details =
10528 isolate->factory()->NewFixedArray(kThreadDetailsSize);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010529
10530 // Thread index 0 is current thread.
10531 if (index == 0) {
10532 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010533 details->set(kThreadDetailsCurrentThreadIndex,
10534 isolate->heap()->true_value());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010535 details->set(kThreadDetailsThreadIdIndex,
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000010536 Smi::FromInt(ThreadId::Current().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010537 } else {
10538 // Find the thread with the requested index.
10539 int n = 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010540 ThreadState* thread =
10541 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010542 while (index != n && thread != NULL) {
10543 thread = thread->Next();
10544 n++;
10545 }
10546 if (thread == NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010547 return isolate->heap()->undefined_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010548 }
10549
10550 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010551 details->set(kThreadDetailsCurrentThreadIndex,
10552 isolate->heap()->false_value());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000010553 details->set(kThreadDetailsThreadIdIndex,
10554 Smi::FromInt(thread->id().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010555 }
10556
10557 // Convert to JS array and return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010558 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010559}
10560
10561
whesse@chromium.orge90029b2010-08-02 11:52:17 +000010562// Sets the disable break state
10563// args[0]: disable break state
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010564RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDisableBreak) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010565 HandleScope scope(isolate);
whesse@chromium.orge90029b2010-08-02 11:52:17 +000010566 ASSERT(args.length() == 1);
10567 CONVERT_BOOLEAN_CHECKED(disable_break, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010568 isolate->debug()->set_disable_break(disable_break);
10569 return isolate->heap()->undefined_value();
whesse@chromium.orge90029b2010-08-02 11:52:17 +000010570}
10571
10572
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010573RUNTIME_FUNCTION(MaybeObject*, Runtime_GetBreakLocations) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010574 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010575 ASSERT(args.length() == 1);
10576
ager@chromium.org5aa501c2009-06-23 07:57:28 +000010577 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
10578 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010579 // Find the number of break points
10580 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010581 if (break_locations->IsUndefined()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010582 // Return array as JS array
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010583 return *isolate->factory()->NewJSArrayWithElements(
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010584 Handle<FixedArray>::cast(break_locations));
10585}
10586
10587
10588// Set a break point in a function
10589// args[0]: function
10590// args[1]: number: break source position (within the function source)
10591// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010592RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFunctionBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010593 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010594 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +000010595 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
10596 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010597 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
10598 RUNTIME_ASSERT(source_position >= 0);
10599 Handle<Object> break_point_object_arg = args.at<Object>(2);
10600
10601 // Set break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010602 isolate->debug()->SetBreakPoint(shared, break_point_object_arg,
10603 &source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010604
lrn@chromium.org32d961d2010-06-30 09:09:34 +000010605 return Smi::FromInt(source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010606}
10607
10608
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010609Object* Runtime::FindSharedFunctionInfoInScript(Isolate* isolate,
10610 Handle<Script> script,
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000010611 int position) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010612 // Iterate the heap looking for SharedFunctionInfo generated from the
10613 // script. The inner most SharedFunctionInfo containing the source position
10614 // for the requested break point is found.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010615 // NOTE: This might require several heap iterations. If the SharedFunctionInfo
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010616 // which is found is not compiled it is compiled and the heap is iterated
10617 // again as the compilation might create inner functions from the newly
10618 // compiled function and the actual requested break point might be in one of
10619 // these functions.
10620 bool done = false;
10621 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +000010622 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010623 Handle<SharedFunctionInfo> target;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010624 while (!done) {
10625 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010626 for (HeapObject* obj = iterator.next();
10627 obj != NULL; obj = iterator.next()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010628 if (obj->IsSharedFunctionInfo()) {
10629 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
10630 if (shared->script() == *script) {
10631 // If the SharedFunctionInfo found has the requested script data and
10632 // contains the source position it is a candidate.
10633 int start_position = shared->function_token_position();
ager@chromium.org236ad962008-09-25 09:45:57 +000010634 if (start_position == RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010635 start_position = shared->start_position();
10636 }
10637 if (start_position <= position &&
10638 position <= shared->end_position()) {
ager@chromium.org32912102009-01-16 10:38:43 +000010639 // If there is no candidate or this function is within the current
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010640 // candidate this is the new candidate.
10641 if (target.is_null()) {
10642 target_start_position = start_position;
10643 target = shared;
10644 } else {
ager@chromium.orga1645e22009-09-09 19:27:10 +000010645 if (target_start_position == start_position &&
10646 shared->end_position() == target->end_position()) {
10647 // If a top-level function contain only one function
10648 // declartion the source for the top-level and the function is
10649 // the same. In that case prefer the non top-level function.
10650 if (!shared->is_toplevel()) {
10651 target_start_position = start_position;
10652 target = shared;
10653 }
10654 } else if (target_start_position <= start_position &&
10655 shared->end_position() <= target->end_position()) {
10656 // This containment check includes equality as a function inside
10657 // a top-level function can share either start or end position
10658 // with the top-level function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010659 target_start_position = start_position;
10660 target = shared;
10661 }
10662 }
10663 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010664 }
10665 }
10666 }
10667
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010668 if (target.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010669 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010670 }
10671
10672 // If the candidate found is compiled we are done. NOTE: when lazy
10673 // compilation of inner functions is introduced some additional checking
10674 // needs to be done here to compile inner functions.
10675 done = target->is_compiled();
10676 if (!done) {
10677 // If the candidate is not compiled compile it to reveal any inner
10678 // functions which might contain the requested source position.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010679 CompileLazyShared(target, KEEP_EXCEPTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010680 }
10681 }
10682
10683 return *target;
10684}
10685
10686
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000010687// Changes the state of a break point in a script and returns source position
10688// where break point was set. NOTE: Regarding performance see the NOTE for
10689// GetScriptFromScriptData.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010690// args[0]: script to set break point in
10691// args[1]: number: break source position (within the script source)
10692// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010693RUNTIME_FUNCTION(MaybeObject*, Runtime_SetScriptBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010694 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010695 ASSERT(args.length() == 3);
10696 CONVERT_ARG_CHECKED(JSValue, wrapper, 0);
10697 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
10698 RUNTIME_ASSERT(source_position >= 0);
10699 Handle<Object> break_point_object_arg = args.at<Object>(2);
10700
10701 // Get the script from the script wrapper.
10702 RUNTIME_ASSERT(wrapper->value()->IsScript());
10703 Handle<Script> script(Script::cast(wrapper->value()));
10704
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000010705 Object* result = Runtime::FindSharedFunctionInfoInScript(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010706 isolate, script, source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010707 if (!result->IsUndefined()) {
10708 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
10709 // Find position within function. The script position might be before the
10710 // source position of the first function.
10711 int position;
10712 if (shared->start_position() > source_position) {
10713 position = 0;
10714 } else {
10715 position = source_position - shared->start_position();
10716 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010717 isolate->debug()->SetBreakPoint(shared, break_point_object_arg, &position);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000010718 position += shared->start_position();
10719 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010720 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010721 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010722}
10723
10724
10725// Clear a break point
10726// args[0]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010727RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010728 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010729 ASSERT(args.length() == 1);
10730 Handle<Object> break_point_object_arg = args.at<Object>(0);
10731
10732 // Clear break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010733 isolate->debug()->ClearBreakPoint(break_point_object_arg);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010734
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010735 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010736}
10737
10738
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010739// Change the state of break on exceptions.
10740// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
10741// args[1]: Boolean indicating on/off.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010742RUNTIME_FUNCTION(MaybeObject*, Runtime_ChangeBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010743 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010744 ASSERT(args.length() == 2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010745 RUNTIME_ASSERT(args[0]->IsNumber());
10746 CONVERT_BOOLEAN_CHECKED(enable, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010747
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010748 // If the number doesn't match an enum value, the ChangeBreakOnException
10749 // function will default to affecting caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010750 ExceptionBreakType type =
10751 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010752 // Update break point state.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010753 isolate->debug()->ChangeBreakOnException(type, enable);
10754 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010755}
10756
10757
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010758// Returns the state of break on exceptions
10759// args[0]: boolean indicating uncaught exceptions
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010760RUNTIME_FUNCTION(MaybeObject*, Runtime_IsBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010761 HandleScope scope(isolate);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010762 ASSERT(args.length() == 1);
10763 RUNTIME_ASSERT(args[0]->IsNumber());
10764
10765 ExceptionBreakType type =
10766 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010767 bool result = isolate->debug()->IsBreakOnException(type);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010768 return Smi::FromInt(result);
10769}
10770
10771
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010772// Prepare for stepping
10773// args[0]: break id for checking execution state
10774// args[1]: step action from the enumeration StepAction
ager@chromium.orga1645e22009-09-09 19:27:10 +000010775// args[2]: number of times to perform the step, for step out it is the number
10776// of frames to step down.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010777RUNTIME_FUNCTION(MaybeObject*, Runtime_PrepareStep) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010778 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010779 ASSERT(args.length() == 3);
10780 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010781 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010782 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10783 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010784 if (!maybe_check->ToObject(&check)) return maybe_check;
10785 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010786 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010787 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010788 }
10789
10790 // Get the step action and check validity.
10791 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
10792 if (step_action != StepIn &&
10793 step_action != StepNext &&
10794 step_action != StepOut &&
10795 step_action != StepInMin &&
10796 step_action != StepMin) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010797 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010798 }
10799
10800 // Get the number of steps.
10801 int step_count = NumberToInt32(args[2]);
10802 if (step_count < 1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010803 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010804 }
10805
ager@chromium.orga1645e22009-09-09 19:27:10 +000010806 // Clear all current stepping setup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010807 isolate->debug()->ClearStepping();
ager@chromium.orga1645e22009-09-09 19:27:10 +000010808
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010809 // Prepare step.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010810 isolate->debug()->PrepareStep(static_cast<StepAction>(step_action),
10811 step_count);
10812 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010813}
10814
10815
10816// Clear all stepping set by PrepareStep.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010817RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearStepping) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010818 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000010819 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010820 isolate->debug()->ClearStepping();
10821 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010822}
10823
10824
10825// Creates a copy of the with context chain. The copy of the context chain is
10826// is linked to the function context supplied.
10827static Handle<Context> CopyWithContextChain(Handle<Context> context_chain,
10828 Handle<Context> function_context) {
10829 // At the bottom of the chain. Return the function context to link to.
10830 if (context_chain->is_function_context()) {
10831 return function_context;
10832 }
10833
10834 // Recursively copy the with contexts.
10835 Handle<Context> previous(context_chain->previous());
10836 Handle<JSObject> extension(JSObject::cast(context_chain->extension()));
danno@chromium.org160a7b02011-04-18 15:51:38 +000010837 Handle<Context> context = CopyWithContextChain(previous, function_context);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010838 return context->GetIsolate()->factory()->NewWithContext(
10839 context, extension, context_chain->IsCatchContext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010840}
10841
10842
10843// Helper function to find or create the arguments object for
10844// Runtime_DebugEvaluate.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010845static Handle<Object> GetArgumentsObject(Isolate* isolate,
10846 JavaScriptFrame* frame,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010847 Handle<JSFunction> function,
ager@chromium.orgb5737492010-07-15 09:29:43 +000010848 Handle<SerializedScopeInfo> scope_info,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010849 const ScopeInfo<>* sinfo,
10850 Handle<Context> function_context) {
10851 // Try to find the value of 'arguments' to pass as parameter. If it is not
10852 // found (that is the debugged function does not reference 'arguments' and
10853 // does not support eval) then create an 'arguments' object.
10854 int index;
10855 if (sinfo->number_of_stack_slots() > 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010856 index = scope_info->StackSlotIndex(isolate->heap()->arguments_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010857 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010858 return Handle<Object>(frame->GetExpression(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010859 }
10860 }
10861
10862 if (sinfo->number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010863 index = scope_info->ContextSlotIndex(isolate->heap()->arguments_symbol(),
10864 NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010865 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010866 return Handle<Object>(function_context->get(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010867 }
10868 }
10869
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000010870 const int length = frame->ComputeParametersCount();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010871 Handle<JSObject> arguments =
10872 isolate->factory()->NewArgumentsObject(function, length);
10873 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010874
10875 AssertNoAllocation no_gc;
10876 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010877 for (int i = 0; i < length; i++) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010878 array->set(i, frame->GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010879 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000010880 arguments->set_elements(*array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010881 return arguments;
10882}
10883
10884
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010885static const char kSourceStr[] =
10886 "(function(arguments,__source__){return eval(__source__);})";
10887
10888
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010889// Evaluate a piece of JavaScript in the context of a stack frame for
ager@chromium.org32912102009-01-16 10:38:43 +000010890// debugging. This is accomplished by creating a new context which in its
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010891// extension part has all the parameters and locals of the function on the
10892// stack frame. A function which calls eval with the code to evaluate is then
10893// compiled in this context and called in this context. As this context
10894// replaces the context of the function on the stack frame a new (empty)
10895// function is created as well to be used as the closure for the context.
10896// This function and the context acts as replacements for the function on the
10897// stack frame presenting the same view of the values of parameters and
10898// local variables as if the piece of JavaScript was evaluated at the point
10899// where the function on the stack frame is currently stopped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010900RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010901 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010902
10903 // Check the execution state and decode arguments frame and source to be
10904 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010905 ASSERT(args.length() == 5);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010906 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010907 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
10908 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010909 if (!maybe_check_result->ToObject(&check_result)) {
10910 return maybe_check_result;
10911 }
10912 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010913 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
10914 CONVERT_ARG_CHECKED(String, source, 2);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000010915 CONVERT_BOOLEAN_CHECKED(disable_break, args[3]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010916 Handle<Object> additional_context(args[4]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000010917
10918 // Handle the processing of break.
10919 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010920
10921 // Get the frame where the debugging is performed.
10922 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010923 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010924 JavaScriptFrame* frame = it.frame();
10925 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +000010926 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010927 ScopeInfo<> sinfo(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010928
10929 // Traverse the saved contexts chain to find the active context for the
10930 // selected frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010931 SaveContext* save = isolate->save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010932 while (save != NULL && !save->below(frame)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010933 save = save->prev();
10934 }
10935 ASSERT(save != NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010936 SaveContext savex(isolate);
10937 isolate->set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010938
10939 // Create the (empty) function replacing the function on the stack frame for
10940 // the purpose of evaluating in the context created below. It is important
10941 // that this function does not describe any parameters and local variables
10942 // in the context. If it does then this will cause problems with the lookup
10943 // in Context::Lookup, where context slots for parameters and local variables
10944 // are looked at before the extension object.
10945 Handle<JSFunction> go_between =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010946 isolate->factory()->NewFunction(isolate->factory()->empty_string(),
10947 isolate->factory()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010948 go_between->set_context(function->context());
10949#ifdef DEBUG
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010950 ScopeInfo<> go_between_sinfo(go_between->shared()->scope_info());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010951 ASSERT(go_between_sinfo.number_of_parameters() == 0);
10952 ASSERT(go_between_sinfo.number_of_context_slots() == 0);
10953#endif
10954
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010955 // Materialize the content of the local scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010956 Handle<JSObject> local_scope = MaterializeLocalScope(isolate, frame);
10957 RETURN_IF_EMPTY_HANDLE(isolate, local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010958
10959 // Allocate a new context for the debug evaluation and set the extension
10960 // object build.
10961 Handle<Context> context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010962 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
10963 go_between);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010964 context->set_extension(*local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010965 // Copy any with contexts present and chain them in front of this context.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010966 Handle<Context> frame_context(Context::cast(frame->context()));
10967 Handle<Context> function_context(frame_context->fcontext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010968 context = CopyWithContextChain(frame_context, context);
10969
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010970 if (additional_context->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010971 context = isolate->factory()->NewWithContext(context,
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010972 Handle<JSObject>::cast(additional_context), false);
10973 }
10974
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010975 // Wrap the evaluation statement in a new function compiled in the newly
10976 // created context. The function has one parameter which has to be called
10977 // 'arguments'. This it to have access to what would have been 'arguments' in
ager@chromium.org32912102009-01-16 10:38:43 +000010978 // the function being debugged.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010979 // function(arguments,__source__) {return eval(__source__);}
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010980
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010981 Handle<String> function_source =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010982 isolate->factory()->NewStringFromAscii(
10983 Vector<const char>(kSourceStr, sizeof(kSourceStr) - 1));
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010984
10985 // Currently, the eval code will be executed in non-strict mode,
10986 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010987 Handle<SharedFunctionInfo> shared =
ager@chromium.org381abbb2009-02-25 13:23:22 +000010988 Compiler::CompileEval(function_source,
10989 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010990 context->IsGlobalContext(),
10991 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010992 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010993 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010994 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010995
10996 // Invoke the result of the compilation to get the evaluation function.
10997 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010998 Handle<Object> receiver(frame->receiver(), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010999 Handle<Object> evaluation_function =
11000 Execution::Call(compiled_function, receiver, 0, NULL,
11001 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000011002 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011003
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011004 Handle<Object> arguments = GetArgumentsObject(isolate, frame,
11005 function, scope_info,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011006 &sinfo, function_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011007
11008 // Invoke the evaluation function and return the result.
11009 const int argc = 2;
11010 Object** argv[argc] = { arguments.location(),
11011 Handle<Object>::cast(source).location() };
11012 Handle<Object> result =
11013 Execution::Call(Handle<JSFunction>::cast(evaluation_function), receiver,
11014 argc, argv, &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000011015 if (has_pending_exception) return Failure::Exception();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011016
11017 // Skip the global proxy as it has no properties and always delegates to the
11018 // real global object.
11019 if (result->IsJSGlobalProxy()) {
11020 result = Handle<JSObject>(JSObject::cast(result->GetPrototype()));
11021 }
11022
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011023 return *result;
11024}
11025
11026
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011027RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluateGlobal) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011028 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011029
11030 // Check the execution state and decode arguments frame and source to be
11031 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011032 ASSERT(args.length() == 4);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011033 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011034 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
11035 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011036 if (!maybe_check_result->ToObject(&check_result)) {
11037 return maybe_check_result;
11038 }
11039 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011040 CONVERT_ARG_CHECKED(String, source, 1);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000011041 CONVERT_BOOLEAN_CHECKED(disable_break, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011042 Handle<Object> additional_context(args[3]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000011043
11044 // Handle the processing of break.
11045 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011046
11047 // Enter the top context from before the debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011048 SaveContext save(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011049 SaveContext* top = &save;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011050 while (top != NULL && *top->context() == *isolate->debug()->debug_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011051 top = top->prev();
11052 }
11053 if (top != NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011054 isolate->set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011055 }
11056
11057 // Get the global context now set to the top context from before the
11058 // debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011059 Handle<Context> context = isolate->global_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011060
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011061 bool is_global = true;
11062
11063 if (additional_context->IsJSObject()) {
11064 // Create a function context first, than put 'with' context on top of it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011065 Handle<JSFunction> go_between = isolate->factory()->NewFunction(
11066 isolate->factory()->empty_string(),
11067 isolate->factory()->undefined_value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011068 go_between->set_context(*context);
11069 context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011070 isolate->factory()->NewFunctionContext(
11071 Context::MIN_CONTEXT_SLOTS, go_between);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011072 context->set_extension(JSObject::cast(*additional_context));
11073 is_global = false;
11074 }
11075
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011076 // Compile the source to be evaluated.
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011077 // Currently, the eval code will be executed in non-strict mode,
11078 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011079 Handle<SharedFunctionInfo> shared =
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011080 Compiler::CompileEval(source, context, is_global, kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011081 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011082 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011083 Handle<JSFunction>(
11084 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
11085 context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011086
11087 // Invoke the result of the compilation to get the evaluation function.
11088 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011089 Handle<Object> receiver = isolate->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011090 Handle<Object> result =
11091 Execution::Call(compiled_function, receiver, 0, NULL,
11092 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000011093 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011094 return *result;
11095}
11096
11097
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011098RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetLoadedScripts) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011099 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000011100 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011101
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011102 // Fill the script objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011103 Handle<FixedArray> instances = isolate->debug()->GetLoadedScripts();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011104
11105 // Convert the script objects to proper JS objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +000011106 for (int i = 0; i < instances->length(); i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +000011107 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
11108 // Get the script wrapper in a local handle before calling GetScriptWrapper,
11109 // because using
11110 // instances->set(i, *GetScriptWrapper(script))
11111 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
11112 // already have deferenced the instances handle.
11113 Handle<JSValue> wrapper = GetScriptWrapper(script);
11114 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011115 }
11116
11117 // Return result as a JS array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011118 Handle<JSObject> result =
11119 isolate->factory()->NewJSObject(isolate->array_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011120 Handle<JSArray>::cast(result)->SetContent(*instances);
11121 return *result;
11122}
11123
11124
11125// Helper function used by Runtime_DebugReferencedBy below.
11126static int DebugReferencedBy(JSObject* target,
11127 Object* instance_filter, int max_references,
11128 FixedArray* instances, int instances_size,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011129 JSFunction* arguments_function) {
11130 NoHandleAllocation ha;
11131 AssertNoAllocation no_alloc;
11132
11133 // Iterate the heap.
11134 int count = 0;
11135 JSObject* last = NULL;
11136 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011137 HeapObject* heap_obj = NULL;
11138 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011139 (max_references == 0 || count < max_references)) {
11140 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011141 if (heap_obj->IsJSObject()) {
11142 // Skip context extension objects and argument arrays as these are
11143 // checked in the context of functions using them.
11144 JSObject* obj = JSObject::cast(heap_obj);
iposva@chromium.org245aa852009-02-10 00:49:54 +000011145 if (obj->IsJSContextExtensionObject() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011146 obj->map()->constructor() == arguments_function) {
11147 continue;
11148 }
11149
11150 // Check if the JS object has a reference to the object looked for.
11151 if (obj->ReferencesObject(target)) {
11152 // Check instance filter if supplied. This is normally used to avoid
11153 // references from mirror objects (see Runtime_IsInPrototypeChain).
11154 if (!instance_filter->IsUndefined()) {
11155 Object* V = obj;
11156 while (true) {
11157 Object* prototype = V->GetPrototype();
11158 if (prototype->IsNull()) {
11159 break;
11160 }
11161 if (instance_filter == prototype) {
11162 obj = NULL; // Don't add this object.
11163 break;
11164 }
11165 V = prototype;
11166 }
11167 }
11168
11169 if (obj != NULL) {
11170 // Valid reference found add to instance array if supplied an update
11171 // count.
11172 if (instances != NULL && count < instances_size) {
11173 instances->set(count, obj);
11174 }
11175 last = obj;
11176 count++;
11177 }
11178 }
11179 }
11180 }
11181
11182 // Check for circular reference only. This can happen when the object is only
11183 // referenced from mirrors and has a circular reference in which case the
11184 // object is not really alive and would have been garbage collected if not
11185 // referenced from the mirror.
11186 if (count == 1 && last == target) {
11187 count = 0;
11188 }
11189
11190 // Return the number of referencing objects found.
11191 return count;
11192}
11193
11194
11195// Scan the heap for objects with direct references to an object
11196// args[0]: the object to find references to
11197// args[1]: constructor function for instances to exclude (Mirror)
11198// args[2]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011199RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugReferencedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011200 ASSERT(args.length() == 3);
11201
11202 // First perform a full GC in order to avoid references from dead objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011203 isolate->heap()->CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011204
11205 // Check parameters.
11206 CONVERT_CHECKED(JSObject, target, args[0]);
11207 Object* instance_filter = args[1];
11208 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
11209 instance_filter->IsJSObject());
11210 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
11211 RUNTIME_ASSERT(max_references >= 0);
11212
11213 // Get the constructor function for context extension and arguments array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011214 JSObject* arguments_boilerplate =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011215 isolate->context()->global_context()->arguments_boilerplate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011216 JSFunction* arguments_function =
11217 JSFunction::cast(arguments_boilerplate->map()->constructor());
11218
11219 // Get the number of referencing objects.
11220 int count;
11221 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000011222 NULL, 0, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011223
11224 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011225 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011226 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011227 if (!maybe_object->ToObject(&object)) return maybe_object;
11228 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011229 FixedArray* instances = FixedArray::cast(object);
11230
11231 // Fill the referencing objects.
11232 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000011233 instances, count, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011234
11235 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011236 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011237 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
11238 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011239 if (!maybe_result->ToObject(&result)) return maybe_result;
11240 }
11241 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011242 return result;
11243}
11244
11245
11246// Helper function used by Runtime_DebugConstructedBy below.
11247static int DebugConstructedBy(JSFunction* constructor, int max_references,
11248 FixedArray* instances, int instances_size) {
11249 AssertNoAllocation no_alloc;
11250
11251 // Iterate the heap.
11252 int count = 0;
11253 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011254 HeapObject* heap_obj = NULL;
11255 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011256 (max_references == 0 || count < max_references)) {
11257 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011258 if (heap_obj->IsJSObject()) {
11259 JSObject* obj = JSObject::cast(heap_obj);
11260 if (obj->map()->constructor() == constructor) {
11261 // Valid reference found add to instance array if supplied an update
11262 // count.
11263 if (instances != NULL && count < instances_size) {
11264 instances->set(count, obj);
11265 }
11266 count++;
11267 }
11268 }
11269 }
11270
11271 // Return the number of referencing objects found.
11272 return count;
11273}
11274
11275
11276// Scan the heap for objects constructed by a specific function.
11277// args[0]: the constructor to find instances of
11278// args[1]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011279RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugConstructedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011280 ASSERT(args.length() == 2);
11281
11282 // First perform a full GC in order to avoid dead objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011283 isolate->heap()->CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011284
11285 // Check parameters.
11286 CONVERT_CHECKED(JSFunction, constructor, args[0]);
11287 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
11288 RUNTIME_ASSERT(max_references >= 0);
11289
11290 // Get the number of referencing objects.
11291 int count;
11292 count = DebugConstructedBy(constructor, max_references, NULL, 0);
11293
11294 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011295 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011296 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011297 if (!maybe_object->ToObject(&object)) return maybe_object;
11298 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011299 FixedArray* instances = FixedArray::cast(object);
11300
11301 // Fill the referencing objects.
11302 count = DebugConstructedBy(constructor, max_references, instances, count);
11303
11304 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011305 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011306 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
11307 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011308 if (!maybe_result->ToObject(&result)) return maybe_result;
11309 }
11310 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011311 return result;
11312}
11313
11314
ager@chromium.orgddb913d2009-01-27 10:01:48 +000011315// Find the effective prototype object as returned by __proto__.
11316// args[0]: the object to find the prototype for.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011317RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPrototype) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011318 ASSERT(args.length() == 1);
11319
11320 CONVERT_CHECKED(JSObject, obj, args[0]);
11321
ager@chromium.orgddb913d2009-01-27 10:01:48 +000011322 // Use the __proto__ accessor.
11323 return Accessors::ObjectPrototype.getter(obj, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011324}
11325
11326
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011327RUNTIME_FUNCTION(MaybeObject*, Runtime_SystemBreak) {
mads.s.ager31e71382008-08-13 09:32:07 +000011328 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011329 CPU::DebugBreak();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011330 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011331}
11332
11333
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011334RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleFunction) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011335#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011336 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011337 ASSERT(args.length() == 1);
11338 // Get the function and make sure it is compiled.
11339 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011340 Handle<SharedFunctionInfo> shared(func->shared());
11341 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011342 return Failure::Exception();
11343 }
11344 func->code()->PrintLn();
11345#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011346 return isolate->heap()->undefined_value();
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011347}
ager@chromium.org9085a012009-05-11 19:22:57 +000011348
11349
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011350RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleConstructor) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011351#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011352 HandleScope scope(isolate);
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011353 ASSERT(args.length() == 1);
11354 // Get the function and make sure it is compiled.
11355 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011356 Handle<SharedFunctionInfo> shared(func->shared());
11357 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011358 return Failure::Exception();
11359 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011360 shared->construct_stub()->PrintLn();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011361#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011362 return isolate->heap()->undefined_value();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011363}
11364
11365
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011366RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetInferredName) {
ager@chromium.org9085a012009-05-11 19:22:57 +000011367 NoHandleAllocation ha;
11368 ASSERT(args.length() == 1);
11369
11370 CONVERT_CHECKED(JSFunction, f, args[0]);
11371 return f->shared()->inferred_name();
11372}
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011373
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011374
11375static int FindSharedFunctionInfosForScript(Script* script,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011376 FixedArray* buffer) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011377 AssertNoAllocation no_allocations;
11378
11379 int counter = 0;
11380 int buffer_size = buffer->length();
11381 HeapIterator iterator;
11382 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
11383 ASSERT(obj != NULL);
11384 if (!obj->IsSharedFunctionInfo()) {
11385 continue;
11386 }
11387 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
11388 if (shared->script() != script) {
11389 continue;
11390 }
11391 if (counter < buffer_size) {
11392 buffer->set(counter, shared);
11393 }
11394 counter++;
11395 }
11396 return counter;
11397}
11398
11399// For a script finds all SharedFunctionInfo's in the heap that points
11400// to this script. Returns JSArray of SharedFunctionInfo wrapped
11401// in OpaqueReferences.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011402RUNTIME_FUNCTION(MaybeObject*,
11403 Runtime_LiveEditFindSharedFunctionInfosForScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011404 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011405 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011406 CONVERT_CHECKED(JSValue, script_value, args[0]);
11407
11408 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
11409
11410 const int kBufferSize = 32;
11411
11412 Handle<FixedArray> array;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011413 array = isolate->factory()->NewFixedArray(kBufferSize);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011414 int number = FindSharedFunctionInfosForScript(*script, *array);
11415 if (number > kBufferSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011416 array = isolate->factory()->NewFixedArray(number);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011417 FindSharedFunctionInfosForScript(*script, *array);
11418 }
11419
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011420 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011421 result->set_length(Smi::FromInt(number));
11422
11423 LiveEdit::WrapSharedFunctionInfos(result);
11424
11425 return *result;
11426}
11427
11428// For a script calculates compilation information about all its functions.
11429// The script source is explicitly specified by the second argument.
11430// The source of the actual script is not used, however it is important that
11431// all generated code keeps references to this particular instance of script.
11432// Returns a JSArray of compilation infos. The array is ordered so that
11433// each function with all its descendant is always stored in a continues range
11434// with the function itself going first. The root function is a script function.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011435RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditGatherCompileInfo) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011436 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011437 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011438 CONVERT_CHECKED(JSValue, script, args[0]);
11439 CONVERT_ARG_CHECKED(String, source, 1);
11440 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
11441
11442 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
11443
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011444 if (isolate->has_pending_exception()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011445 return Failure::Exception();
11446 }
11447
11448 return result;
11449}
11450
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011451// Changes the source of the script to a new_source.
11452// If old_script_name is provided (i.e. is a String), also creates a copy of
11453// the script with its original source and sends notification to debugger.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011454RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011455 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011456 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011457 CONVERT_CHECKED(JSValue, original_script_value, args[0]);
11458 CONVERT_ARG_CHECKED(String, new_source, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011459 Handle<Object> old_script_name(args[2], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011460
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011461 CONVERT_CHECKED(Script, original_script_pointer,
11462 original_script_value->value());
11463 Handle<Script> original_script(original_script_pointer);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011464
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011465 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
11466 new_source,
11467 old_script_name);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011468
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011469 if (old_script->IsScript()) {
11470 Handle<Script> script_handle(Script::cast(old_script));
11471 return *(GetScriptWrapper(script_handle));
11472 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011473 return isolate->heap()->null_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011474 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011475}
11476
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011477
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011478RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSourceUpdated) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011479 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011480 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011481 CONVERT_ARG_CHECKED(JSArray, shared_info, 0);
11482 return LiveEdit::FunctionSourceUpdated(shared_info);
11483}
11484
11485
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011486// Replaces code of SharedFunctionInfo with a new one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011487RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceFunctionCode) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011488 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011489 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011490 CONVERT_ARG_CHECKED(JSArray, new_compile_info, 0);
11491 CONVERT_ARG_CHECKED(JSArray, shared_info, 1);
11492
ager@chromium.orgac091b72010-05-05 07:34:42 +000011493 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011494}
11495
11496// Connects SharedFunctionInfo to another script.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011497RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSetScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011498 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011499 HandleScope scope(isolate);
11500 Handle<Object> function_object(args[0], isolate);
11501 Handle<Object> script_object(args[1], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011502
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011503 if (function_object->IsJSValue()) {
11504 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
11505 if (script_object->IsJSValue()) {
11506 CONVERT_CHECKED(Script, script, JSValue::cast(*script_object)->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011507 script_object = Handle<Object>(script, isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011508 }
11509
11510 LiveEdit::SetFunctionScript(function_wrapper, script_object);
11511 } else {
11512 // Just ignore this. We may not have a SharedFunctionInfo for some functions
11513 // and we check it in this function.
11514 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011515
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011516 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011517}
11518
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011519
11520// In a code of a parent function replaces original function as embedded object
11521// with a substitution one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011522RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceRefToNestedFunction) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011523 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011524 HandleScope scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011525
11526 CONVERT_ARG_CHECKED(JSValue, parent_wrapper, 0);
11527 CONVERT_ARG_CHECKED(JSValue, orig_wrapper, 1);
11528 CONVERT_ARG_CHECKED(JSValue, subst_wrapper, 2);
11529
11530 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
11531 subst_wrapper);
11532
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011533 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011534}
11535
11536
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011537// Updates positions of a shared function info (first parameter) according
11538// to script source change. Text change is described in second parameter as
11539// array of groups of 3 numbers:
11540// (change_begin, change_end, change_end_new_position).
11541// Each group describes a change in text; groups are sorted by change_begin.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011542RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditPatchFunctionPositions) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011543 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011544 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011545 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
11546 CONVERT_ARG_CHECKED(JSArray, position_change_array, 1);
11547
ager@chromium.orgac091b72010-05-05 07:34:42 +000011548 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011549}
11550
11551
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011552// For array of SharedFunctionInfo's (each wrapped in JSValue)
11553// checks that none of them have activations on stacks (of any thread).
11554// Returns array of the same length with corresponding results of
11555// LiveEdit::FunctionPatchabilityStatus type.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011556RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCheckAndDropActivations) {
ager@chromium.org357bf652010-04-12 11:30:10 +000011557 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011558 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011559 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
ager@chromium.org357bf652010-04-12 11:30:10 +000011560 CONVERT_BOOLEAN_CHECKED(do_drop, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011561
ager@chromium.org357bf652010-04-12 11:30:10 +000011562 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011563}
11564
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000011565// Compares 2 strings line-by-line, then token-wise and returns diff in form
11566// of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
11567// of diff chunks.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011568RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCompareStrings) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011569 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011570 HandleScope scope(isolate);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011571 CONVERT_ARG_CHECKED(String, s1, 0);
11572 CONVERT_ARG_CHECKED(String, s2, 1);
11573
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000011574 return *LiveEdit::CompareStrings(s1, s2);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011575}
11576
11577
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011578// A testing entry. Returns statement position which is the closest to
11579// source_position.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011580RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionCodePositionFromSource) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011581 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011582 HandleScope scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011583 CONVERT_ARG_CHECKED(JSFunction, function, 0);
11584 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11585
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011586 Handle<Code> code(function->code(), isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011587
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011588 if (code->kind() != Code::FUNCTION &&
11589 code->kind() != Code::OPTIMIZED_FUNCTION) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011590 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011591 }
11592
11593 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011594 int closest_pc = 0;
11595 int distance = kMaxInt;
11596 while (!it.done()) {
11597 int statement_position = static_cast<int>(it.rinfo()->data());
11598 // Check if this break point is closer that what was previously found.
11599 if (source_position <= statement_position &&
11600 statement_position - source_position < distance) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +000011601 closest_pc =
11602 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011603 distance = statement_position - source_position;
11604 // Check whether we can't get any closer.
11605 if (distance == 0) break;
11606 }
11607 it.next();
11608 }
11609
11610 return Smi::FromInt(closest_pc);
11611}
11612
11613
ager@chromium.org357bf652010-04-12 11:30:10 +000011614// Calls specified function with or without entering the debugger.
11615// This is used in unit tests to run code as if debugger is entered or simply
11616// to have a stack with C++ frame in the middle.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011617RUNTIME_FUNCTION(MaybeObject*, Runtime_ExecuteInDebugContext) {
ager@chromium.org357bf652010-04-12 11:30:10 +000011618 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011619 HandleScope scope(isolate);
ager@chromium.org357bf652010-04-12 11:30:10 +000011620 CONVERT_ARG_CHECKED(JSFunction, function, 0);
11621 CONVERT_BOOLEAN_CHECKED(without_debugger, args[1]);
11622
11623 Handle<Object> result;
11624 bool pending_exception;
11625 {
11626 if (without_debugger) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011627 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000011628 &pending_exception);
11629 } else {
11630 EnterDebugger enter_debugger;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011631 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000011632 &pending_exception);
11633 }
11634 }
11635 if (!pending_exception) {
11636 return *result;
11637 } else {
11638 return Failure::Exception();
11639 }
11640}
11641
11642
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011643// Sets a v8 flag.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011644RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFlags) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011645 CONVERT_CHECKED(String, arg, args[0]);
11646 SmartPointer<char> flags =
11647 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
11648 FlagList::SetFlagsFromString(*flags, StrLength(*flags));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011649 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011650}
11651
11652
11653// Performs a GC.
11654// Presently, it only does a full GC.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011655RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectGarbage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011656 isolate->heap()->CollectAllGarbage(true);
11657 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011658}
11659
11660
11661// Gets the current heap usage.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011662RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHeapUsage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011663 int usage = static_cast<int>(isolate->heap()->SizeOfObjects());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011664 if (!Smi::IsValid(usage)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011665 return *isolate->factory()->NewNumberFromInt(usage);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011666 }
11667 return Smi::FromInt(usage);
11668}
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011669
11670
11671// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011672RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLOLEnabled) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011673#ifdef LIVE_OBJECT_LIST
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011674 return isolate->heap()->true_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011675#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011676 return isolate->heap()->false_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011677#endif
11678}
11679
11680
11681// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011682RUNTIME_FUNCTION(MaybeObject*, Runtime_CaptureLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011683#ifdef LIVE_OBJECT_LIST
11684 return LiveObjectList::Capture();
11685#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011686 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011687#endif
11688}
11689
11690
11691// Deletes the specified live object list.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011692RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011693#ifdef LIVE_OBJECT_LIST
11694 CONVERT_SMI_CHECKED(id, args[0]);
11695 bool success = LiveObjectList::Delete(id);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011696 return success ? isolate->heap()->true_value() :
11697 isolate->heap()->false_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011698#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011699 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011700#endif
11701}
11702
11703
11704// Generates the response to a debugger request for a dump of the objects
11705// contained in the difference between the captured live object lists
11706// specified by id1 and id2.
11707// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
11708// dumped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011709RUNTIME_FUNCTION(MaybeObject*, Runtime_DumpLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011710#ifdef LIVE_OBJECT_LIST
11711 HandleScope scope;
11712 CONVERT_SMI_CHECKED(id1, args[0]);
11713 CONVERT_SMI_CHECKED(id2, args[1]);
11714 CONVERT_SMI_CHECKED(start, args[2]);
11715 CONVERT_SMI_CHECKED(count, args[3]);
11716 CONVERT_ARG_CHECKED(JSObject, filter_obj, 4);
11717 EnterDebugger enter_debugger;
11718 return LiveObjectList::Dump(id1, id2, start, count, filter_obj);
11719#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011720 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011721#endif
11722}
11723
11724
11725// Gets the specified object as requested by the debugger.
11726// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011727RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011728#ifdef LIVE_OBJECT_LIST
11729 CONVERT_SMI_CHECKED(obj_id, args[0]);
11730 Object* result = LiveObjectList::GetObj(obj_id);
11731 return result;
11732#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011733 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011734#endif
11735}
11736
11737
11738// Gets the obj id for the specified address if valid.
11739// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011740RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjId) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011741#ifdef LIVE_OBJECT_LIST
11742 HandleScope scope;
11743 CONVERT_ARG_CHECKED(String, address, 0);
11744 Object* result = LiveObjectList::GetObjId(address);
11745 return result;
11746#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011747 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011748#endif
11749}
11750
11751
11752// Gets the retainers that references the specified object alive.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011753RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjRetainers) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011754#ifdef LIVE_OBJECT_LIST
11755 HandleScope scope;
11756 CONVERT_SMI_CHECKED(obj_id, args[0]);
11757 RUNTIME_ASSERT(args[1]->IsUndefined() || args[1]->IsJSObject());
11758 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsBoolean());
11759 RUNTIME_ASSERT(args[3]->IsUndefined() || args[3]->IsSmi());
11760 RUNTIME_ASSERT(args[4]->IsUndefined() || args[4]->IsSmi());
11761 CONVERT_ARG_CHECKED(JSObject, filter_obj, 5);
11762
11763 Handle<JSObject> instance_filter;
11764 if (args[1]->IsJSObject()) {
11765 instance_filter = args.at<JSObject>(1);
11766 }
11767 bool verbose = false;
11768 if (args[2]->IsBoolean()) {
11769 verbose = args[2]->IsTrue();
11770 }
11771 int start = 0;
11772 if (args[3]->IsSmi()) {
11773 start = Smi::cast(args[3])->value();
11774 }
11775 int limit = Smi::kMaxValue;
11776 if (args[4]->IsSmi()) {
11777 limit = Smi::cast(args[4])->value();
11778 }
11779
11780 return LiveObjectList::GetObjRetainers(obj_id,
11781 instance_filter,
11782 verbose,
11783 start,
11784 limit,
11785 filter_obj);
11786#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011787 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011788#endif
11789}
11790
11791
11792// Gets the reference path between 2 objects.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011793RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLPath) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011794#ifdef LIVE_OBJECT_LIST
11795 HandleScope scope;
11796 CONVERT_SMI_CHECKED(obj_id1, args[0]);
11797 CONVERT_SMI_CHECKED(obj_id2, args[1]);
11798 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsJSObject());
11799
11800 Handle<JSObject> instance_filter;
11801 if (args[2]->IsJSObject()) {
11802 instance_filter = args.at<JSObject>(2);
11803 }
11804
11805 Object* result =
11806 LiveObjectList::GetPath(obj_id1, obj_id2, instance_filter);
11807 return result;
11808#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011809 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011810#endif
11811}
11812
11813
11814// Generates the response to a debugger request for a list of all
11815// previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011816RUNTIME_FUNCTION(MaybeObject*, Runtime_InfoLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011817#ifdef LIVE_OBJECT_LIST
11818 CONVERT_SMI_CHECKED(start, args[0]);
11819 CONVERT_SMI_CHECKED(count, args[1]);
11820 return LiveObjectList::Info(start, count);
11821#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011822 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011823#endif
11824}
11825
11826
11827// Gets a dump of the specified object as requested by the debugger.
11828// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011829RUNTIME_FUNCTION(MaybeObject*, Runtime_PrintLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011830#ifdef LIVE_OBJECT_LIST
11831 HandleScope scope;
11832 CONVERT_SMI_CHECKED(obj_id, args[0]);
11833 Object* result = LiveObjectList::PrintObj(obj_id);
11834 return result;
11835#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011836 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011837#endif
11838}
11839
11840
11841// Resets and releases all previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011842RUNTIME_FUNCTION(MaybeObject*, Runtime_ResetLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011843#ifdef LIVE_OBJECT_LIST
11844 LiveObjectList::Reset();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011845 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011846#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011847 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011848#endif
11849}
11850
11851
11852// Generates the response to a debugger request for a summary of the types
11853// of objects in the difference between the captured live object lists
11854// specified by id1 and id2.
11855// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
11856// summarized.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011857RUNTIME_FUNCTION(MaybeObject*, Runtime_SummarizeLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011858#ifdef LIVE_OBJECT_LIST
11859 HandleScope scope;
11860 CONVERT_SMI_CHECKED(id1, args[0]);
11861 CONVERT_SMI_CHECKED(id2, args[1]);
11862 CONVERT_ARG_CHECKED(JSObject, filter_obj, 2);
11863
11864 EnterDebugger enter_debugger;
11865 return LiveObjectList::Summarize(id1, id2, filter_obj);
11866#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011867 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011868#endif
11869}
11870
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011871#endif // ENABLE_DEBUGGER_SUPPORT
11872
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011873
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011874#ifdef ENABLE_LOGGING_AND_PROFILING
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011875RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerResume) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011876 NoHandleAllocation ha;
ager@chromium.org5c838252010-02-19 08:53:10 +000011877 ASSERT(args.length() == 2);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011878
11879 CONVERT_CHECKED(Smi, smi_modules, args[0]);
ager@chromium.org5c838252010-02-19 08:53:10 +000011880 CONVERT_CHECKED(Smi, smi_tag, args[1]);
11881 v8::V8::ResumeProfilerEx(smi_modules->value(), smi_tag->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011882 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011883}
11884
11885
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011886RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerPause) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011887 NoHandleAllocation ha;
ager@chromium.org5c838252010-02-19 08:53:10 +000011888 ASSERT(args.length() == 2);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011889
11890 CONVERT_CHECKED(Smi, smi_modules, args[0]);
ager@chromium.org5c838252010-02-19 08:53:10 +000011891 CONVERT_CHECKED(Smi, smi_tag, args[1]);
11892 v8::V8::PauseProfilerEx(smi_modules->value(), smi_tag->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011893 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011894}
11895
11896#endif // ENABLE_LOGGING_AND_PROFILING
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011897
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011898// Finds the script object from the script data. NOTE: This operation uses
11899// heap traversal to find the function generated for the source position
11900// for the requested break point. For lazily compiled functions several heap
11901// traversals might be required rendering this operation as a rather slow
11902// operation. However for setting break points which is normally done through
11903// some kind of user interaction the performance is not crucial.
11904static Handle<Object> Runtime_GetScriptFromScriptName(
11905 Handle<String> script_name) {
11906 // Scan the heap for Script objects to find the script with the requested
11907 // script data.
11908 Handle<Script> script;
11909 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011910 HeapObject* obj = NULL;
11911 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011912 // If a script is found check if it has the script data requested.
11913 if (obj->IsScript()) {
11914 if (Script::cast(obj)->name()->IsString()) {
11915 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
11916 script = Handle<Script>(Script::cast(obj));
11917 }
11918 }
11919 }
11920 }
11921
11922 // If no script with the requested script data is found return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011923 if (script.is_null()) return FACTORY->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011924
11925 // Return the script found.
11926 return GetScriptWrapper(script);
11927}
11928
11929
11930// Get the script object from script data. NOTE: Regarding performance
11931// see the NOTE for GetScriptFromScriptData.
11932// args[0]: script data for the script to find the source for
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011933RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011934 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011935
11936 ASSERT(args.length() == 1);
11937
11938 CONVERT_CHECKED(String, script_name, args[0]);
11939
11940 // Find the requested script.
11941 Handle<Object> result =
11942 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
11943 return *result;
11944}
11945
11946
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011947// Determines whether the given stack frame should be displayed in
11948// a stack trace. The caller is the error constructor that asked
11949// for the stack trace to be collected. The first time a construct
11950// call to this function is encountered it is skipped. The seen_caller
11951// in/out parameter is used to remember if the caller has been seen
11952// yet.
11953static bool ShowFrameInStackTrace(StackFrame* raw_frame, Object* caller,
11954 bool* seen_caller) {
11955 // Only display JS frames.
11956 if (!raw_frame->is_java_script())
11957 return false;
11958 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
11959 Object* raw_fun = frame->function();
11960 // Not sure when this can happen but skip it just in case.
11961 if (!raw_fun->IsJSFunction())
11962 return false;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011963 if ((raw_fun == caller) && !(*seen_caller)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011964 *seen_caller = true;
11965 return false;
11966 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011967 // Skip all frames until we've seen the caller. Also, skip the most
11968 // obvious builtin calls. Some builtin calls (such as Number.ADD
11969 // which is invoked using 'call') are very difficult to recognize
11970 // so we're leaving them in for now.
11971 return *seen_caller && !frame->receiver()->IsJSBuiltinsObject();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011972}
11973
11974
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011975// Collect the raw data for a stack trace. Returns an array of 4
11976// element segments each containing a receiver, function, code and
11977// native code offset.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011978RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectStackTrace) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011979 ASSERT_EQ(args.length(), 2);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011980 Handle<Object> caller = args.at<Object>(0);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011981 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[1]);
11982
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011983 HandleScope scope(isolate);
11984 Factory* factory = isolate->factory();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011985
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000011986 limit = Max(limit, 0); // Ensure that limit is not negative.
11987 int initial_size = Min(limit, 10);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011988 Handle<FixedArray> elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011989 factory->NewFixedArrayWithHoles(initial_size * 4);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011990
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011991 StackFrameIterator iter(isolate);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011992 // If the caller parameter is a function we skip frames until we're
11993 // under it before starting to collect.
11994 bool seen_caller = !caller->IsJSFunction();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011995 int cursor = 0;
11996 int frames_seen = 0;
11997 while (!iter.done() && frames_seen < limit) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011998 StackFrame* raw_frame = iter.frame();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011999 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012000 frames_seen++;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012001 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000012002 // Set initial size to the maximum inlining level + 1 for the outermost
12003 // function.
12004 List<FrameSummary> frames(Compiler::kMaxInliningLevels + 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012005 frame->Summarize(&frames);
12006 for (int i = frames.length() - 1; i >= 0; i--) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012007 if (cursor + 4 > elements->length()) {
12008 int new_capacity = JSObject::NewElementsCapacity(elements->length());
12009 Handle<FixedArray> new_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012010 factory->NewFixedArrayWithHoles(new_capacity);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012011 for (int i = 0; i < cursor; i++) {
12012 new_elements->set(i, elements->get(i));
12013 }
12014 elements = new_elements;
12015 }
12016 ASSERT(cursor + 4 <= elements->length());
12017
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012018 Handle<Object> recv = frames[i].receiver();
12019 Handle<JSFunction> fun = frames[i].function();
12020 Handle<Code> code = frames[i].code();
12021 Handle<Smi> offset(Smi::FromInt(frames[i].offset()));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012022 elements->set(cursor++, *recv);
12023 elements->set(cursor++, *fun);
12024 elements->set(cursor++, *code);
12025 elements->set(cursor++, *offset);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012026 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012027 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012028 iter.Advance();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012029 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012030 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012031 result->set_length(Smi::FromInt(cursor));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012032 return *result;
12033}
12034
12035
ager@chromium.org3811b432009-10-28 14:53:37 +000012036// Returns V8 version as a string.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012037RUNTIME_FUNCTION(MaybeObject*, Runtime_GetV8Version) {
ager@chromium.org3811b432009-10-28 14:53:37 +000012038 ASSERT_EQ(args.length(), 0);
12039
12040 NoHandleAllocation ha;
12041
12042 const char* version_string = v8::V8::GetVersion();
12043
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012044 return isolate->heap()->AllocateStringFromAscii(CStrVector(version_string),
12045 NOT_TENURED);
ager@chromium.org3811b432009-10-28 14:53:37 +000012046}
12047
12048
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012049RUNTIME_FUNCTION(MaybeObject*, Runtime_Abort) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012050 ASSERT(args.length() == 2);
12051 OS::PrintError("abort: %s\n", reinterpret_cast<char*>(args[0]) +
12052 Smi::cast(args[1])->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012053 isolate->PrintStack();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012054 OS::Abort();
12055 UNREACHABLE();
12056 return NULL;
12057}
12058
12059
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012060RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFromCache) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012061 // This is only called from codegen, so checks might be more lax.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012062 CONVERT_CHECKED(JSFunctionResultCache, cache, args[0]);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012063 Object* key = args[1];
12064
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012065 int finger_index = cache->finger_index();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012066 Object* o = cache->get(finger_index);
12067 if (o == key) {
12068 // The fastest case: hit the same place again.
12069 return cache->get(finger_index + 1);
12070 }
12071
12072 for (int i = finger_index - 2;
12073 i >= JSFunctionResultCache::kEntriesIndex;
12074 i -= 2) {
12075 o = cache->get(i);
12076 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012077 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012078 return cache->get(i + 1);
12079 }
12080 }
12081
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012082 int size = cache->size();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012083 ASSERT(size <= cache->length());
12084
12085 for (int i = size - 2; i > finger_index; i -= 2) {
12086 o = cache->get(i);
12087 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012088 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012089 return cache->get(i + 1);
12090 }
12091 }
12092
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012093 // There is no value in the cache. Invoke the function and cache result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012094 HandleScope scope(isolate);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012095
12096 Handle<JSFunctionResultCache> cache_handle(cache);
12097 Handle<Object> key_handle(key);
12098 Handle<Object> value;
12099 {
12100 Handle<JSFunction> factory(JSFunction::cast(
12101 cache_handle->get(JSFunctionResultCache::kFactoryIndex)));
12102 // TODO(antonm): consider passing a receiver when constructing a cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012103 Handle<Object> receiver(isolate->global_context()->global());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012104 // This handle is nor shared, nor used later, so it's safe.
12105 Object** argv[] = { key_handle.location() };
12106 bool pending_exception = false;
12107 value = Execution::Call(factory,
12108 receiver,
12109 1,
12110 argv,
12111 &pending_exception);
12112 if (pending_exception) return Failure::Exception();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012113 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012114
12115#ifdef DEBUG
12116 cache_handle->JSFunctionResultCacheVerify();
12117#endif
12118
12119 // Function invocation may have cleared the cache. Reread all the data.
12120 finger_index = cache_handle->finger_index();
12121 size = cache_handle->size();
12122
12123 // If we have spare room, put new data into it, otherwise evict post finger
12124 // entry which is likely to be the least recently used.
12125 int index = -1;
12126 if (size < cache_handle->length()) {
12127 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize);
12128 index = size;
12129 } else {
12130 index = finger_index + JSFunctionResultCache::kEntrySize;
12131 if (index == cache_handle->length()) {
12132 index = JSFunctionResultCache::kEntriesIndex;
12133 }
12134 }
12135
12136 ASSERT(index % 2 == 0);
12137 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
12138 ASSERT(index < cache_handle->length());
12139
12140 cache_handle->set(index, *key_handle);
12141 cache_handle->set(index + 1, *value);
12142 cache_handle->set_finger_index(index);
12143
12144#ifdef DEBUG
12145 cache_handle->JSFunctionResultCacheVerify();
12146#endif
12147
12148 return *value;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012149}
12150
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012151
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012152RUNTIME_FUNCTION(MaybeObject*, Runtime_NewMessageObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012153 HandleScope scope(isolate);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012154 CONVERT_ARG_CHECKED(String, type, 0);
12155 CONVERT_ARG_CHECKED(JSArray, arguments, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012156 return *isolate->factory()->NewJSMessageObject(
12157 type,
12158 arguments,
12159 0,
12160 0,
12161 isolate->factory()->undefined_value(),
12162 isolate->factory()->undefined_value(),
12163 isolate->factory()->undefined_value());
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012164}
12165
12166
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012167RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetType) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012168 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12169 return message->type();
12170}
12171
12172
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012173RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetArguments) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012174 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12175 return message->arguments();
12176}
12177
12178
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012179RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetStartPosition) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012180 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12181 return Smi::FromInt(message->start_position());
12182}
12183
12184
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012185RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetScript) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012186 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12187 return message->script();
12188}
12189
12190
kasper.lund44510672008-07-25 07:37:58 +000012191#ifdef DEBUG
12192// ListNatives is ONLY used by the fuzz-natives.js in debug mode
12193// Exclude the code in release mode.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012194RUNTIME_FUNCTION(MaybeObject*, Runtime_ListNatives) {
mads.s.ager31e71382008-08-13 09:32:07 +000012195 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012196 HandleScope scope;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012197#define COUNT_ENTRY(Name, argc, ressize) + 1
12198 int entry_count = 0
12199 RUNTIME_FUNCTION_LIST(COUNT_ENTRY)
12200 INLINE_FUNCTION_LIST(COUNT_ENTRY)
12201 INLINE_RUNTIME_FUNCTION_LIST(COUNT_ENTRY);
12202#undef COUNT_ENTRY
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012203 Factory* factory = isolate->factory();
12204 Handle<FixedArray> elements = factory->NewFixedArray(entry_count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012205 int index = 0;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012206 bool inline_runtime_functions = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +000012207#define ADD_ENTRY(Name, argc, ressize) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012208 { \
12209 HandleScope inner; \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012210 Handle<String> name; \
12211 /* Inline runtime functions have an underscore in front of the name. */ \
12212 if (inline_runtime_functions) { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012213 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012214 Vector<const char>("_" #Name, StrLength("_" #Name))); \
12215 } else { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012216 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012217 Vector<const char>(#Name, StrLength(#Name))); \
12218 } \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012219 Handle<FixedArray> pair_elements = factory->NewFixedArray(2); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012220 pair_elements->set(0, *name); \
12221 pair_elements->set(1, Smi::FromInt(argc)); \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012222 Handle<JSArray> pair = factory->NewJSArrayWithElements(pair_elements); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012223 elements->set(index++, *pair); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012224 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012225 inline_runtime_functions = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012226 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012227 inline_runtime_functions = true;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012228 INLINE_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012229 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012230#undef ADD_ENTRY
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012231 ASSERT_EQ(index, entry_count);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012232 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012233 return *result;
12234}
kasper.lund44510672008-07-25 07:37:58 +000012235#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012236
12237
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012238RUNTIME_FUNCTION(MaybeObject*, Runtime_Log) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000012239 ASSERT(args.length() == 2);
ager@chromium.org381abbb2009-02-25 13:23:22 +000012240 CONVERT_CHECKED(String, format, args[0]);
12241 CONVERT_CHECKED(JSArray, elms, args[1]);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000012242 Vector<const char> chars = format->ToAsciiVector();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012243 LOGGER->LogRuntime(chars, elms);
12244 return isolate->heap()->undefined_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000012245}
12246
12247
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012248RUNTIME_FUNCTION(MaybeObject*, Runtime_IS_VAR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012249 UNREACHABLE(); // implemented as macro in the parser
12250 return NULL;
12251}
12252
12253
12254// ----------------------------------------------------------------------------
12255// Implementation of Runtime
12256
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012257#define F(name, number_of_args, result_size) \
12258 { Runtime::k##name, Runtime::RUNTIME, #name, \
12259 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012260
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012261
12262#define I(name, number_of_args, result_size) \
12263 { Runtime::kInline##name, Runtime::INLINE, \
12264 "_" #name, NULL, number_of_args, result_size },
12265
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012266static const Runtime::Function kIntrinsicFunctions[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012267 RUNTIME_FUNCTION_LIST(F)
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012268 INLINE_FUNCTION_LIST(I)
12269 INLINE_RUNTIME_FUNCTION_LIST(I)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012270};
12271
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012272
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012273MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Heap* heap,
12274 Object* dictionary) {
12275 ASSERT(Isolate::Current()->heap() == heap);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012276 ASSERT(dictionary != NULL);
12277 ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
12278 for (int i = 0; i < kNumFunctions; ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000012279 Object* name_symbol;
12280 { MaybeObject* maybe_name_symbol =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012281 heap->LookupAsciiSymbol(kIntrinsicFunctions[i].name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012282 if (!maybe_name_symbol->ToObject(&name_symbol)) return maybe_name_symbol;
12283 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012284 StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012285 { MaybeObject* maybe_dictionary = string_dictionary->Add(
12286 String::cast(name_symbol),
12287 Smi::FromInt(i),
12288 PropertyDetails(NONE, NORMAL));
12289 if (!maybe_dictionary->ToObject(&dictionary)) {
12290 // Non-recoverable failure. Calling code must restart heap
12291 // initialization.
12292 return maybe_dictionary;
12293 }
12294 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012295 }
12296 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012297}
12298
12299
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012300const Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
12301 Heap* heap = name->GetHeap();
12302 int entry = heap->intrinsic_function_names()->FindEntry(*name);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012303 if (entry != kNotFound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012304 Object* smi_index = heap->intrinsic_function_names()->ValueAt(entry);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012305 int function_index = Smi::cast(smi_index)->value();
12306 return &(kIntrinsicFunctions[function_index]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012307 }
12308 return NULL;
12309}
12310
12311
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012312const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012313 return &(kIntrinsicFunctions[static_cast<int>(id)]);
12314}
12315
12316
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012317void Runtime::PerformGC(Object* result) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000012318 Isolate* isolate = Isolate::Current();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012319 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000012320 if (failure->IsRetryAfterGC()) {
12321 // Try to do a garbage collection; ignore it if it fails. The C
12322 // entry stub will throw an out-of-memory exception in that case.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000012323 isolate->heap()->CollectGarbage(failure->allocation_space());
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000012324 } else {
12325 // Handle last resort GC and make sure to allow future allocations
12326 // to grow the heap without causing GCs (if possible).
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000012327 isolate->counters()->gc_last_resort_from_js()->Increment();
12328 isolate->heap()->CollectAllGarbage(false);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000012329 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012330}
12331
12332
12333} } // namespace v8::internal